【问题标题】:Powermock verify private static method call in static methodPowermock 验证静态方法中的私有静态方法调用
【发布时间】:2019-07-26 08:53:27
【问题描述】:

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

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

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】:

    结果确实很复杂。

    如果这可以工作,解决方案可能会按照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 参数匹配器。确保导入正确!

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

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

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

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

    所以,真正的答案是:

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

    验证私有方法是否被调用是没有意义的。您的公共方法的调用者应该返回“什么进去,什么回来”。在那个级别上,其他任何事情都应该无关紧要。

    鉴于 OP 的评论:

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

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

    【讨论】:

    • 我添加了 PowerMockito.doReturn("whatever").when(ClassUnderTest.class, "anotherPrivateStaticMethod","something");甚至没有在测试路径中调用它并且测试通过了。基于此,我相信没有什么不隐式验证。另外,为什么我不应该测试这些东西。这些称为交互测试,需要测试这种交互。 Powermock 仅用于测试静态交互。当状态没有保存时​​,静态不是问题
    • @RayS 在阅读了更多内容后,我修改了大部分答案。我希望 A) 技术解决方案现在适用于您和 B) 我建议完全不这样做的理由更有说服力。除此之外,我希望您能欣赏我在这里投入的时间和精力 ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-14
    • 2019-10-28
    • 1970-01-01
    • 1970-01-01
    • 2013-05-03
    相关资源
    最近更新 更多