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

问题描述 投票:0回答:1

我想知道是否有一种方法可以验证和调用为从被测试的公共静态方法调用的私有静态方法创建的模拟。

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

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是否被调用?

java unit-testing powermock powermockito
1个回答
1
投票

结果真的很复杂。

如果这可以工作,解决方案可能沿着写的here。不幸的是我没有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()匹配器,而any()将是(Power)Mockito参数匹配器。确保导入正确!

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

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

但真正的要点是:你不应该测试这样的东西。您的公共方法如何获得其结果对您的测试完全无关紧要。您的公共方法有一个契约,如何实现它是一个实现细节。

您的方法将您的单元测试变为(过于复杂!)重新实现您的生产代码。这意味着:您打算更改实施的第二个,您的测试需要进行调整。更糟糕的是,因为你将方法名称作为原始字符串传递,你甚至不会注意到运行时,突然之间方法停止返回whatever,但给你dummy

所以,这里真正的答案是:

  • 首先,尽可能避免静态,因此您不会涉及模拟静态方法的业务
  • 忘记测试这样的实现细节。

验证私有方法是否被调用是没有意义的。您的公共方法的调用者应该返回“进入的内容和返回的内容”。在那个级别上任何其他事情都不重要。

鉴于OP的评论:

  • 静态问题比“状态”还要多。它杀死了多态性,并且它还导致对静态代码所在的类的直接,硬依赖
  • 这使得不仅单元测试更难,任何类型的测试都变得困难
  • 根据我的个人经验:当人们告诉我“我需要PowerMock(ito)用于我新编写的代码”时,我知道他们创建了难以测试的代码而无需这样做。编写生产代码是绝对可能的(也是可取的),可以用较少侵入性的模拟框架进行测试。

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

© www.soinside.com 2019 - 2024. All rights reserved.