对于任何复杂的 Guice 项目,您应该添加测试以确保模块可用于创建您的类。在您的示例中,如果 B 是 Guice 无法弄清楚如何创建的类型,那么 Guice 将无法创建 A。如果启动服务器不需要 A,但在您的服务器处理 a 时需要 A请求,这会导致问题。
在我的项目中,我为重要的模块编写测试。对于每个模块,我使用requireBinding() 来声明模块需要但未定义的绑定。在我的测试中,我使用被测模块和另一个提供所需绑定的模块创建了一个 Guice 注入器。下面是一个使用 JUnit4 和 JMock 的示例:
/** Module that provides LoginService */
public class LoginServiceModule extends AbstractModule {
@Override
protected void configure() {
requireBinding(UserDao.class);
}
@Provides
LoginService provideLoginService(UserDao dao) {
...
}
}
@RunWith(JMock.class)
public class LoginServiceModuleTest {
private final Mockery context = new Mockery();
@Test
public void testModule() {
Injector injector = Guice.createInjector(
new LoginServiceModule(), new ModuleDeps());
// next line will throw an exception if dependencies missing
injector.getProvider(LoginService.class);
}
private class ModuleDeps extends AbstractModule {
private final UserDao fakeUserDao;
public ModuleDeps() {
fakeUserDao = context.mock(UserDao.class);
}
@Override
protected void configure() {}
@Provides
Server provideUserDao() {
return fakeUserDao;
}
}
}
请注意测试如何只要求提供者。这足以确定 Guice 可以解决绑定问题。如果 LoginService 是由 provider 方法创建的,则此测试不会测试 provider 方法中的代码。
此测试也不会测试您是否将正确的东西绑定到UserDao,或者UserDao 的范围是否正确。有些人会争辩说,这些类型的东西很少值得检查。如果有问题,它会发生一次。你应该“测试直到恐惧变成无聊。”
我发现模块测试很有用,因为我经常添加新的注入点,而且很容易忘记添加绑定。
requireBinding() 调用可以帮助 Guice 在返回注入器之前捕获丢失的绑定!在上面的示例中,如果没有 requireBinding() 调用,测试仍然可以工作,但我喜欢使用它们,因为它们用作文档。
对于更复杂的模块(比如我的根模块),我可能会使用Modules.override() 来覆盖我在测试时不想要的绑定(例如,如果我想验证我的根对象是否被创建,我可能不希望它创建将连接到数据库的对象)。对于简单的项目,您可能只测试顶级模块。
请注意,Guice will not inject nulls 除非该字段使用 @Nullable 注释,因此您很少需要在测试中验证注入的对象是否非空。事实上,当我用@Inject 注释构造函数时,我不会费心检查参数是否为null(事实上,我的测试经常将null 注入构造函数以保持测试简单)。