模拟静态类

6

我有一个类中的方法,它实例化了一个静态类实例并对其进行操作。

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() {
      }
   }
}

如何模拟静态类实例化,以便我可以在不经过静态类构造函数的情况下模拟 callSomeMethod() ?

你根本不应该在SomeClass中实例化MyStaticClass。你应该使用依赖反转MyStaticClass的实例注入到SomeClass的实例中。 - Timothy Truckle
2个回答

2
你可以使用PowerMock来模拟实例化静态内部类。这可以通过准备实际实例化静态内部类的类来完成,因此在这里,它将是您定义了方法someMethod()的类。
假设someMethod()被定义在MyOtherClass类中并且不返回任何内容,则您的测试类应该如下所示:
@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();
    }
}

假设我的类 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");
        }
    }
}

我的类 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

关于如何构造新对象的更多详细信息,请参见如何模拟构造新对象


是的,这很清楚,但它并没有起作用。当执行 new MyClass.MyStaticClass( arg1, arg2, arg3 ); 时,程序会进入静态类的构造函数中,而我想要避免这种情况。 - jerome
我没有在定义静态类的公共类内部实例化它,这就是与你的代码的区别。 - jerome
2
我将 @PrepareForTest(MyClass.class) 替换为 @PrepareForTest(SomeClass .class),现在它可以正常工作了。非常感谢您提供的代码示例,对我帮助很大。 - jerome

0

我写了一个更简单的工具,用于模拟通常“无法模拟”的事物,位于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();
}

}

```


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接