我如何测试Guice注射? [英] How do I test Guice injections?

查看:77
本文介绍了我如何测试Guice注射?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我向Google Guice提供了连接我的物品的责任。但是,我如何测试绑定是否运行良好?



例如,假设我们有一个类 A 它具有依赖 B 。如何测试B是否正确注入?

  A类{
private B b;
public A(){}

@Inject
public void setB(B b){
this.b = b
}
}

请注意 A 尚未获得一个 getB()方法,我想声明 Ab 不是 null

解决方案

对于任何复杂的Guice项目,您应该添加测试以确保可以使用这些模块创建你的类。在你的例子中,如果B是Guice无法弄清楚如何创建的类型,那么Guice将无法创建A.如果A不需要启动服务器但是在服务器处理时需要请求,这会导致问题。



在我的项目中,我为非平凡的模块编写测试。对于每个模块,我使用 requireBinding()声明模块需要绑定但未定义的绑定。在我的测试中,我使用被测模块创建了一个Guice注入器,另一个模块提供了所需的绑定。下面是使用JUnit4和JMock的示例:

  / **提供LoginService的模块* / 
公共类LoginServiceModule扩展AbstractModule {
@Override
protected void configure(){
requireBinding(UserDao.class);
}

@Provides
LoginService provideLoginService(UserDao dao){
...
}
}

@RunWith(JMock.class)
公共类LoginServiceModuleTest {
private final Mockery context = new Mockery();

@Test
public void testModule(){
Injector injector = Guice.createInjector(
new LoginServiceModule(),new ModuleDeps());

//如果依赖项缺少
injector.getProvider(LoginService.class),则下一行将抛出异常;
}

私有类ModuleDeps扩展AbstractModule {
私有最终UserDao fakeUserDao;

public ModuleDeps(){
fakeUserDao = context.mock(UserDao.class);
}

@Override
protected void configure(){}

@Provides
Server provideUserDao(){
return fakeUserDao;
}
}
}

注意测试如何只询问对于提供者。这足以确定Guice可以解决绑定问题。如果LoginService是由提供者方法创建的,则此测试不会测试提供者方法中的代码。



此测试也不测试您绑定了正确的东西到 UserDao ,或 UserDao 的范围是正确的。有人会争辩说,那些类型的东西很少值得检查;如果有问题,它会发生一次。你应该测试直到恐惧变成无聊。



我发现模块测试很有用,因为我经常添加新的注入点,而且很容易忘记添加绑定。 / p>

requireBinding()调用可以帮助Guice在返回注入器之前捕获缺失的绑定!在上面的例子中,如果 requireBinding()调用不在那里,测试仍然有效,但我喜欢它们,因为它们用作文档。



对于更复杂的模块(比如我的根模块),我可以使用 Modules.override()覆盖我在测试中不需要的绑定时间(例如,如果我想验证我的根对象是否要创建,我可能不希望它创建一个将连接到数据库的对象)。对于简单项目,您可能只测试顶级模块。



请注意Guice 不会注入空值除非该字段用 @Nullable 注释,所以你很少需要验证注入的对象在测试中是非null的。事实上,当我使用 @Inject 注释构造函数时,我不打算检查参数是否为 null (实际上,我的测试经常在构造函数中注入 null 以保持测试简单。)


I gave to Google Guice the responsibility of wiring my objects. But, how can I test if the bindings are working well?

For example, suppose we have a class A which has a dependence B. How can I test that B is injected correctly?

class A {
    private B b;
    public A() {}

    @Inject
    public void setB(B b) {
        this.b = b
    }
}

Notice that A hasn't got a getB() method and I want to assert that A.b isn't null.

解决方案

For any complex Guice project, you should add tests to make sure that the modules can be used to create your classes. In your example, if B were a type that Guice couldn't figure out how to create, then Guice won't be able to create A. If A wasn't needed to start the server but was needed when your server was handling a request, that would cause problems.

In my projects, I write tests for non-trivial modules. For each module, I use requireBinding() to declare what bindings the module requires but doesn't define. In my tests, I create a Guice injector using the module under test and another module that provides the required bindings. Here's an example using JUnit4 and 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;
    }
  }
}

Notice how the test only asks for a provider. That's sufficient to determine that Guice could resolve the bindings. If LoginService was created by a provider method, this test wouldn't test the code in the provider method.

This test also doesn't test that you binded the right thing to UserDao, or that UserDao was scoped correctly. Some would argue that those types of things are rarely worth checking; if there's a problem, it happens once. You should "test until fear turns to boredom."

I find Module tests useful because I often add new injection points, and it's easy to forget to add a binding.

The requireBinding() calls can help Guice catch missing bindings before it returns your injector! In the above example, the test would still work if the requireBinding() calls were not there, but I like having them because they serve as documentation.

For more complicated modules (like my root module) I might use Modules.override() to override bindings that I don't want at test time (for instance, if I want to verify that my root object to be created, I probably don't want it to create an object that will connect to the database). For simple projects, you might only test the top-level module.

Note that Guice will not inject nulls unless the field as annotated with @Nullable so you very rarely need to verify that the injected objects are non-null in your tests. In fact, when I annotate constructors with @Inject I do not bother to check if the parameters are null (in fact, my tests often inject null into the constructor to keep the tests simple).

这篇关于我如何测试Guice注射?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆