模拟静态 class

Mocking static class

我在 class 中有一个方法可以实例化静态 class 实例并对其调用操作。

public class SomeClass {
    public void someMethod() {
       MyClass.MyStaticClass myStaticClassInstance =
          new MyClass.MyStaticClass( arg1, arg2, arg3 );
       myStaticClassInstance.callSomeMethod();
    }
}

public class MyClass {

   public static class MyStaticClass {

      public MyStaticClass( Object arg1, Object arg2, Object arg3 ) {
      }

      public void callSomeMethod() {
      }
   }
}

如何模拟静态 class 实例化,以便我可以模拟 callSomeMethod() 而无需通过静态 class 构造函数?

您可以使用 PowerMock 通过模拟静态内部 class 的实例化来做到这一点。这可以通过准备 class 来完成,该 class 实际上会实例化您的静态内部 class,因此这里将是 class,您在其中定义了方法 someMethod()

假设 someMethod() 定义到 class MyOtherClass 和 returns 什么都没有,你的测试 class 将是这样的:

@RunWith(PowerMockRunner.class) // The runner of PowerMock
@PrepareForTest(MyOtherClass.class) // the class to prepare
public class MyClassTest {

    @Test
    public void test() throws Exception {
        // The mock of your static inner class to return
        MyClass.MyStaticClass mock = Mockito.mock(MyClass.MyStaticClass.class);
        // Mock the call of callSomeMethod()
        PowerMockito.doAnswer(
            new Answer<Void>() {
                @Override
                public Void answer(final InvocationOnMock invocation) throws Throwable {
                    // Do something here as new implementation of callSomeMethod
                    System.out.println("My new Answer");
                    return null;
                }
            }
        ).when(mock).callSomeMethod();
        // Return your mock in case we instantiate MyClass.MyStaticClass in 
        // the prepared class with any arguments  
        PowerMockito.whenNew(MyClass.MyStaticClass.class)
            .withArguments(Matchers.any(), Matchers.any(), Matchers.any())
            .thenReturn(mock);

        // The code that will call someMethod
        MyOtherClass mc = new MyOtherClass();
        mc.someMethod();
    }
}

假设我的 class MyClass 看起来像这样:

public class MyClass {

    public static class MyStaticClass {
        public MyStaticClass(Object arg1, Object arg2, Object arg3) {
            System.out.println("Called constructor");
        }

        public void callSomeMethod() {
            System.out.println("callSomeMethod");
        }
    }
}

我的 class MyOtherClass 看起来像这样:

public class MyOtherClass {
    public void someMethod() {
        MyClass.MyStaticClass myStaticClassInstance = new MyClass.MyStaticClass(
            new Object(), new Object(), new Object()
        );
        myStaticClassInstance.callSomeMethod();
    }
}

如果我启动测试,我会得到预期的结果:

My new Answer

而不是我应该默认得到的:

Called constructor
callSomeMethod

有关 how to constructions of new objects 的更多详细信息。

我写了一个更简单的工具来模拟通常 'non-mockable' 在 https://github.com/iirekm/misc/tree/master/ajmock

的东西

您的代码可以如下所示:

``` public class MyClassTest {

@Test
public void test() throws Exception {
    MyClass.MyStaticClass mock = Mockito.mock(MyClass.MyStaticClass.class);
    when(() -> mock.callSomeMethod()).thenAnswer(() -> ...);

    when(() -> new MyClass.MyStaticClass(any(), any(), any())).thenReturn(mock);

    // The code that will call someMethod
    MyOtherClass mc = new MyOtherClass();
    mc.someMethod();
}

}

```