注入内联 Mockito 静态方法

Inject inline Mockito static methods

我正在使用 JUnit4 测试 class 并且目标 class 使用依赖静态方法来创建对象,这里是目标 class 中的相关代码片段:

private static final Dependency DEPENDENCY_CLIENT = Dependency.getInstance();

我知道从 Mockito 的 3.4.0 版本开始,增加了模拟静态方法的能力,例如,我可以这样做:

try (MockedStatic<Dependency> mocked = mockStatic(Dependency.class)) {
  mocked.when(Dependency::getInstance).thenReturn(dependency);
  Dependency test = Dependency.getInstance();
  mocked.verify(Dependency::getInstance);
}

dependency 变量只是 class 的简单模拟版本。

但是,我要测试的 class 在其构造函数中进行了此调用,所以有没有办法让我的目标 class 在期间调用模拟的 getInstance() 方法它的初始化?

我不确定你遇到了什么问题。下面的代码对我有用(我使用的是 JUnit 5,但这应该没什么区别)

@ExtendWith(MockitoExtension.class)
public class MockEg {
    static class Dependency {
        public static Dependency getInstance() {
            return new Dependency();
        }
        public String getMessage() {
            return "I am not a mock";
        }
    }

    static class ClassToTest {

        private final Dependency dependency;
        public ClassToTest() {
            this.dependency = Dependency.getInstance();
        }

        public String getDependencyMessage() {
            return dependency.getMessage();
        }
    }

    @Test
    public void aTest() {
        try (MockedStatic<Dependency> mocked = mockStatic(Dependency.class)) {
            Dependency dependency = mock(Dependency.class);
            when(dependency.getMessage()).thenReturn("I am a mock");
            mocked.when(Dependency::getInstance).thenReturn(dependency);
            ClassToTest c = new ClassToTest();
            assertThat(c.getDependencyMessage(), Matchers.is("I am a mock"));
            mocked.verify(Dependency::getInstance);
        }
    }
}

处理这种情况的正确方法是将 class 与 static 分离,方法是引入一个可以模拟的接口:

    interface DependencyProvider {
        Dependency getDependency();
    }
    
    class ClassToTest2 {

        private final DependencyProvider dependencyProvider;
        public ClassToTest2(DependencyProvider dependencyProvider) {

            this.dependencyProvider = dependencyProvider;
        }

        public String getDependencyMessage() {
            return dependencyProvider.getDependency().getMessage();
        }
    }