简体   繁体   English

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

[英]Powermock verify private static method call in static method

I would like to know if there is a way to verify and call made to a mock created for a private static method called from a public static method under test. 我想知道是否有一种方法可以验证并调用为从测试中的公共静态方法调用的私有静态方法创建的模拟程序。

Here is my public static method under test 这是我正在测试的公共静态方法

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

private static String privateStaticMethod(String p1){
        return "dummy";
}

I have mocked the private static method using powermokito as follows: 我使用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");            
    }
}

Now, is there a way to verify that privateStaticMethod was called ? 现在,有没有一种方法可以验证privateStaticMethod被调用了?

Turns out to be really complicated. 原来真的很复杂。

If this can be made to work, the solution goes probably along what is written up here . 如果这可以奏效,则解决方案可能会遵循此处的内容 Unfortunately I don't have a PowerMockito setup, so I can't test this code myself: 不幸的是我没有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"));

The above uses the Hamcrest is() matcher, and any() would be a (Power)Mockito argument matcher. 上面使用了Hamcrest is()匹配器, any()将是(Power)Mockito参数匹配器。 Make sure that the imports are correct! 确保导入正确!

The above should fail when you change your public method and don't invoke that private method, and/or return something else. 当您更改公用方法并且不调用该专用方法和/或返回其他内容时,以上操作将失败。

But the real answer is: you should avoid such kind of tests. 但是真正的答案是:您应该避免这种测试。 The above code implicitly verifies that this private method was called: if it isn't called, you should receive a different result! 上面的代码隐式验证了此私有方法的调用:如果未调用该私有方法,您将收到不同的结果!

But the real point here is: you shouldn't be testing such things. 但是这里的真正意义是:您不应该测试这些东西。 How your public method gets to its result shouldn't matter to to your tests at all. 您的公共方法如何获得其结果与您的测试完全无关。 Your public method has a contract, and how that is implemented is an implementation detail . 您的公共方法有一个合同,如何实现是实现细节

Your approach turns your unit test into a (overly complex!) re-implementation of your production code. 您的方法将单元测试转变为生产代码的(过于复杂!)重新实现。 That means: the second you intend to change your implementation your test needs to be adapted. 这意味着:您打算更改实施的第二次测试就需要调整。 Worse, because you pass the method name as raw string, you won't even notice until runtime, when all of a sudden the method stops returning whatever , but gives you dummy . 更糟糕的是,由于您将方法名称作为原始字符串传递,因此您甚至不会注意到,直到运行时,该方法突然停止返回whatever ,而给了dummy

So, the real answer here is: 因此,这里的真正答案是:

  • first of all avoid static where possible, so you don't get into the business of mocking static methods 首先,尽可能避免使用静态方法,因此您无需从事模拟静态方法的工作
  • forget about testing such implementation details. 忘记测试这样的实现细节。

It is pointless to verify that the private method was called. 验证是否调用了私有方法毫无意义 A caller of your public method should return about "what goes in, and what comes back". 您的公共方法的调用者应该返回“什么进来,什么回来”的信息。 Anything else should not matter on that level. 在该级别上,其他任何内容都无关紧要。

And given the OP's comment: 并给出了OP的评论:

  • there are way more problems to static than just "state". 除了“状态”之外,还有更多的静态问题。 It kills polymorphism, and it also leads to a direct, hard dependency to the class where the static code lives 它杀死了多态性,并且还导致对静态代码所在类的直接,硬性依赖
  • that makes not only unit testing harder, any kind of test becomes hard 这不仅使单元测试更加困难,而且任何类型的测试都变得更加困难
  • and from my personal experience: when people tell me "I need PowerMock(ito) for my newly written code" then I know that they created hard-to-test code without the need to do so. 从我的个人经验来看:当人们告诉我“我的新编写的代码需要PowerMock(ito)”时,我知道他们无需这样做就可以创建难以测试的代码。 It is absolutely possible (and desirable) to write production code in ways that can nicely be tested with less intrusive mocking frameworks. 绝对有可能(并且很希望)以可以用较少侵入性的模拟框架很好地测试的方式编写生产代码。

In other words: if you can't write a simple straight forward test in Mockito, then most likely you created hard to test production code, and you it would be much better to invest time and energy to make the production code easier to test. 换句话说:如果您不能在Mockito中编写简单的直接测试,那么很可能您创建了难以测试的生产代码,那么最好花时间和精力使生产代码更容易测试。 Instead of using the PowerMock(ito) hammer to "fix" your problem by working around symptoms. 而不是使用PowerMock(ito)锤通过解决症状来“解决”您的问题。 And yes, this matters. 是的,这很重要。 We came from a PowerMock-based "too much static" code base, and simply told people at some point "no more". 我们来自基于PowerMock的“太多静态”代码库,只是在某个时候告诉人们“不再”。 Since then, when we need mocking, we use Mockito. 从那时起,当我们需要模拟时,我们使用Mockito。 And the number of bizarre "unit test fails" due to "change to static" in a different place went down to 0. And our production code became better . 由于在不同地方“更改为静态”而导致的离奇的“单元测试失败”的数量下降到0。我们的生产代码变得更好

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM