Mockito和Guice:模拟@Provides方法

axzmvihb  于 2022-11-08  发布在  其他
关注(0)|答案(2)|浏览(218)

我的类中有一个名为MainModule的模块,它有各种绑定,其中一个绑定是到我的自定义服务接口HttpClientPool的绑定

public class MainModule extends AbstractVertxModule{
        binder.bind(HttpClientPool.class).to(HttpClientPoolImpl.class).in(Singleton.class);
        // other bindings
} 

@Provides @Singleton
    public TokenClient tokenClient(HttpClientPool clientPool){
        return new TokenClient(clientPool);
}

该模块也是一个名为tokenClient的对象的提供者,如上所示。
tokenClient被注入到不同类的其他位置,并且在此对象上调用了一些方法。
在我的单元测试中,我打算使用Mockito来获得一个模拟的tokenClient对象。这意味着,我希望MainModule提供一个模拟的对象,而不是一个真正的对象。我尝试使用一个如下所示的testMainModule:

public class testMainModile implements Module{
    private TokenClient tokenClient;

    public TokenModule(TokenClient client) {
        this.tokenClient= client;
    }

    @Override
    public void configure(Binder binder) {
        binder.bind(TokenClient.class).toInstance(tokenClient);
    }
}

下面是我的单元测试的一段摘录:

@Mock
private TokenClient tokenClient;
// Stuff between
Injector messagingInjector = Guice.createInjector(new TestMainModule(tokenClient));
        mainModule = messagingInjector.getInstance(MainModule.class);

不知怎么的,我得到的只是mainModule对象中的一个真实对象。我是否遗漏了什么?

b91juud3

b91juud31#

我假设你有一个提供一些功能的类,这就是你要进行单元测试的类,它需要你注入一个tokenClient才能正常工作,所以你面临的问题是:当我测试被测试的类时,它是如何被注入一个模拟的tockenClient的。
有几种可能性......可能最简单的一种是严格地只使用构造函数注入,通过“new”创建被测类的示例,然后将单独创建的模拟示例交给它们。
如果你想坚持使用guice,可以使用override Bindings and Providers,甚至提供完全隔离的测试模块。
我更喜欢使用needle4j框架(我是一个贡献者,所以我有偏见),一个依赖注入模拟器,默认情况下注入模拟,除非配置为其他方式。如果使用正确(坚持一个类单元,不要试图设置集成级测试),这可能是最快和最简单的方式来测试依赖于注入示例的类。

weylhg0b

weylhg0b2#

如果你 * 需要 * 覆盖绑定(例如,如果你不能修改MainModule),下面是一个完整的工作示例:

class MainModuleTest {
    @Mock
    @Bind
    TokenClient tokenClient;

    @Test
    public void testHelloWorldClient() {
        MockitoAnnotations.openMocks(this);

        Module testMainModule = Modules.override(new MainModule())
                .with(BoundFieldModule.of(this)

        ...
    }
}

备注:

  • 您将需要在guice-testlib上添加依赖项
  • 通过这种方法,我们可以取消类TestMainModule

工作原理:

  • BoundFieldModule.of(this)使用测试类中所有用@Bind注解的字段动态创建一个测试模块。由于tokenClient也是一个mock示例,因此模块中的绑定将包含mock。
  • Modules.overrideBoundFieldModule覆盖在MainModule上。具体地,
  • 它将使用mock TokenClient,因为它优先于BoundFieldModule中的绑定;和
  • 它将使用真实的HttpClientPool,因为这仅在MainModule中有界。

我不确定获取testMainModule示例的意义是什么。如果我们想从测试模块中获取HttpClientPool的示例,我们可以这样做:

class MainModuleTest {
    @Mock
    @Bind
    TokenClient tokenClient;

    @Inject
    HttpClientPool httpClientPool;

    @Test
    public void testHelloWorldClient() {
        MockitoAnnotations.openMocks(this);

        injector = Guice.createInjector(
            Modules.override(new MainModule()).with(BoundFieldModule.of(this))
        )
        injector.injectMembers(this)

        httpClientPool.doStuff()
    }
}

在这种情况下,注入器使用被重写的模块将HttpClientPoolImpl的示例注入到httpClientPool字段中。

相关问题