Java 静态方法中的Powermock验证私有静态方法调用

Java 静态方法中的Powermock验证私有静态方法调用,java,unit-testing,powermock,powermockito,Java,Unit Testing,Powermock,Powermockito,我想知道是否有一种方法可以验证和调用为私有静态方法创建的mock,该方法是从测试中的公共静态方法调用的 这是我正在测试的公共静态方法 public static String methodUnderTest(String p1){ return privateStaticMethod(p1); } private static String privateStaticMethod(String p1){ return "dummy"; } 我使用powermokito模

我想知道是否有一种方法可以验证和调用为私有静态方法创建的mock,该方法是从测试中的公共静态方法调用的

这是我正在测试的公共静态方法

public static String methodUnderTest(String p1){
   return privateStaticMethod(p1);
}

private static String privateStaticMethod(String p1){
        return "dummy";
}
我使用powermokito模拟了私有静态方法,如下所示:

@RunWith(PowerMockRunner.class)
@PrepareForTest(fullyQualifiedNames = "ClassUnderTest")
public class ClassUnderTestTest {

    @Test
    public void test_sometest() throws Exception {
         PowerMockito.spy(ClassUnderTest.class);

         PowerMockito.doReturn("whatever").when(ClassUnderTest.class, "privateStaticMethod","something");

         String retValue =  ClassUnderTest.methodUnderTest("something");  
         assertEquals(retValue, "whatever");            
    }
}

现在,有没有办法验证调用了privateStaticMethod?

结果非常复杂

如果这可以实现,那么解决方案很可能会遵循所写的原则。不幸的是,我没有PowerMockito设置,因此我无法亲自测试此代码:

// tell powermock(ito) that you want to do PARTIAL static mocking
PowerMockito.spy(ClassUnderTest.class);
// give it the mocking SPEC for that static method that needs mocking
PowerMockito.doReturn("whatever").when(ClassUnderTest.class, "privateStaticMethod","something");
// tell it to INVOKE the real method when the public one is called
PowerMockito.doCallRealMethod().when(Util, "methodUnderTest", any());

// now assert that the mock spec kicked in
assertThat(ClassUnderTest.methodUnderTest("something"), is("whatever"));
上面使用了Hamcrest
is()
matcher,而
any()
将是一个(Power)Mockito参数匹配器。确保导入是正确的

当您更改公共方法并且不调用该私有方法和/或返回其他内容时,上述操作将失败

但真正的答案是:你应该避免这样的测试。上面的代码隐式地验证是否调用了这个私有方法:如果没有调用它,您应该会收到不同的结果

但这里真正的要点是:你不应该测试这些东西您的公共方法如何达到其结果对您的测试根本不重要。您的公共方法有一个契约,如何实现它是一个实现细节

您的方法将单元测试转变为生产代码的(过于复杂!)重新实现。这意味着:一旦您打算更改实现,您的测试就需要进行调整。更糟糕的是,因为您将方法名作为原始字符串传递,所以直到运行时,您才注意到,当方法突然停止返回
whatever
,而是给您
dummy

因此,真正的答案是:

  • 首先,在可能的情况下避免使用静态方法,这样您就不会从事模拟静态方法的工作
  • 忘记测试这些实现细节吧
验证是否调用了私有方法是毫无意义的。公共方法的调用方应该返回关于“什么进入,什么返回”。在这个层面上,其他任何事情都不重要

鉴于OP的评论:

  • 静态的问题远不止“状态”。它消除了多态性,还导致了对静态代码所在的类的直接、硬依赖
  • 这不仅使单元测试更加困难,而且任何类型的测试都变得困难
  • 从我个人的经验来看:当人们告诉我“我需要PowerMock(ito)来编写新编写的代码”时,我知道他们创建了难以测试的代码,而不需要这样做。完全有可能(也希望)以可以用侵入性较小的模拟框架很好地测试的方式编写生产代码

换句话说:如果你不能用Mockito编写一个简单的直接测试,那么很可能你创建了难以测试的生产代码,你最好投入时间和精力使生产代码更容易测试。而不是使用PowerMock(ito)锤子通过解决症状来“修复”问题。是的,这很重要。我们来自一个基于PowerMock的“太多静态”代码库,并在某个时候简单地告诉人们“不再”。从那时起,当我们需要嘲弄时,我们就使用嘲弄。由于在另一个地方“更改为静态”而导致的奇怪的“单元测试失败”数量降到了0。我们的生产代码变得更好。

我添加了PowerMockito.doReturn(“无论什么”)。当(ClassUnderTest.class,“另一个私有静态方法”,“某物”);它甚至没有在测试路径中调用,测试通过了。基于这一点,我相信没有任何东西不能隐式地验证。还有,为什么我不应该测试这些东西。这些被称为交互测试,需要测试这些交互。创建Powermock只是为了测试静态交互。当状态未保存时,静态不是problem@RayS在读了更多的书之后,我修改了大部分的答案。我希望A)技术解决方案现在对您有效,B)我建议不这样做的理由更具说服力。除此之外,我希望你们感谢我在这里投入的时间和精力;-)