如何在没有powermock的情况下模拟静态方法

时间:2017-07-07 09:20:28

标签: java junit mockito powermock

有没有办法在junit中测试时模拟静态util方法?

我知道Powermock可以模拟静态调用;但我不想使用Powermock。

还有其他选择吗?

4 个答案:

答案 0 :(得分:10)

(我假设你可以使用Mockito)我没有任何专注,但我倾向于使用以下策略:

1)在被测试的类中,使用包装静态调用本身的包级别方法调用替换静态直接调用:

public class ToBeTested{

    public void myMethodToTest(){
         ...
         String s = makeStaticWrappedCall();
         ...
    }

    String makeStaticWrappedCall(){
        return Util.staticMethodCall();
    }
}

2)在测试时监视被测试的类并模拟包装的包级别方法:

public class ToBeTestedTest{

    @Spy
    ToBeTested tbTestedSpy = new ToBeTested();

    @Before
    public void init(){
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void myMethodToTestTest() throws Exception{
       // Arrange
       doReturn("Expected String").when(tbTestedSpy).makeStaticWrappedCall();

       // Act
       tbTestedSpy.myMethodToTest();
    }
}

答案 1 :(得分:4)

当您拥有静态代码时,会给您的单元测试带来麻烦;所以你觉得你必须“嘲笑它”,你有这些选择:

  • 您转向PowerMock(ito)。工作正常。
  • 你转向JMockit。工作得很好。
  • 如果您正在测试自己编写的代码,您可能想退后一步问自己:“为什么我编写的代码现在很难进行单元测试?”

换句话说:如果你想使用一个模拟框架,你必须使用上面列出的那个。一方面,这绝对是公平的。 static 是Java语言的一部分;那么为什么不使用一个允许你处理它的框架呢?

但当然:您的生产代码中仍然存在静态调用。导致紧耦合,并阻止多态

所以:如果你可以摆脱静态调用(即使只是使用其他答案中建议的解决方法) - 那就更好了。如果不是:Mockito无能为力;你需要字节码操作的神奇之处。 JVM代理。

答案 2 :(得分:1)

您可以使用Mockito(自3.4.0版本开始)来模拟静态方法。

给出一个类Foo

class Foo{
  static String method() {
    return "foo";
  }
}

这是测试:

@Test
void testMethod() {
    assertEquals("foo", Foo.method());
    try (MockedStatic mocked = Mockito.mockStatic(Foo.class)) {
        mocked.when(Foo::method).thenReturn("bar");
        assertEquals("bar", Foo.method());
        mocked.verify(Foo::method);
    }
    assertEquals("foo", Foo.method());
}

这需要依赖项org.mockito:mockito-inline:3.4.0或更高版本。

答案 3 :(得分:0)

我做得和Maciej在上面他的回答中所建议的类似,因此很幸运。在Java8中,我喜欢用功能接口包装这些静态方法,以使其更直接地进行注入或模拟。例如:

public class MyClass {
    private MyStaticWrapper staticWrapper;

    public MyClass(final MyStaticWrapper staticWrapper) {
        this.staticWrapper = staticWrapper;
    }

    public void main() {
        ...
        staticWrapper.doSomething();
        ...    
    }
}    

public interface MyStaticWrapper {
    default void doSomething() {
      Util.annoyingUntestableStaticFunction();
    }
}