Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I test Guice injections?

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.

like image 820
yeraycaballero Avatar asked Mar 15 '10 14:03

yeraycaballero


People also ask

How do you test a Guice?

Typically the best way to test Guice modules is to just create an injector in your test and ensure you can get instances of keys you care about out of it. To do this without causing production stuff to happen you may need to replace some modules with other modules. You can use Modules.

How does a Guice injection work?

Using GuiceIn each of your constructors that need to have something injected in them, you just add an @Inject annotation and that tells Guice to do it's thing. Guice figures out how to give you an Emailer based on the type. If it's a simple object, it'll instantiate it and pass it in.

What is Google inject Guice?

Google Guice (pronounced like "juice") is an open-source software framework for the Java platform released by Google under the Apache License. It provides support for dependency injection using annotations to configure Java objects.


1 Answers

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).

like image 166
NamshubWriter Avatar answered Sep 20 '22 08:09

NamshubWriter