Showing posts with label Dependency Injection. Show all posts
Showing posts with label Dependency Injection. Show all posts

Saturday, December 15, 2007

Synergy Between Guice, Easymock and JUnit

I have recently written separate posts about Guice and Easymock. Those posts were really just preparation for this one. Guice and Easymock are impressive tools each on their own. However they really shine when used together and in conjunction with JUnit (or your testing framework of choice). If you are unfamiliar with either of these tools please read the previous posts to get up to speed before continuing reading.
Synergistic Effects:
Arrows indicate that one tool is increasing the value of the tool to which the arrow points.

Easymock --> JUnit:
  • Higher signal to noise ratio in tests since manual mocks are unnecessary. This increases the expressiveness of the tests and increases the value of the tests as executable documentation.
JUnit --> Guice:
  • Unit testing code leads most people eventually into some form of dependency injection. Thus Guice often just makes easier the best-practices that a developer is already following.
Guice --> JUnit:
  • Classes can use injected dependencies rather than relying on concrete implementations, allowing tests to be targeted on solely on the class under test.
  • Individual test classes do not need to construct collaborator objects as a prerequisite for instantiating the class under test. They can simply have Guice build an instance of the class under test.
  • Collaborators that are necessary for the intent of the test can be injected directly into test classes (see below).
  • Collaborators that are not important in achieving the goal of the test can be ignored.
Guice <--> Easymock:
  • Mock collaborators can be configured in a Guice configuation Module intended specifically for testing.
  • The testing Module is reusable to the same work to generate mocks won't have to be done in multiple test classes.

Object can be injected directly into tests. You still want to instantiate your own class under test, but this is very useful for collaborator objects that are not the focus of the test. The following example does not show the use of the injected object, only that the injection is possible:


@RunWith(InjectingTestClassMethodsRunner.class)
public class InjectionTest {
@Inject IClock clock;

@Test
public void myTest() {
assertNotNull(clock);
}
}


Here is a snippet to show you how to use Guice to instantiate your test classes in JUnit:

public class InjectingTestClassMethodsRunner extends TestClassMethodsRunner {
public InjectingTestClassMethodsRunner(Class klass) {
super(klass);
}

@Override
protected Object createTest() throws Exception {
Injector injector = Guice.createInjector(new TestModule());
return injector.getInstance(this.getTestClass());
}
}

Simple Dependency Injection with Guice

Google's Guice is a very slick, annotations-based Dependency Injection framework. It allows you to easily create class instances even if they have complex dependencies on other classes. The knowledge of what concrete implementation to use for a dependency is contained in simple configuration classes called Modules. Injection sites for these implementations may be constructors, methods, or fields. Anywhere you want a dependency to be injected you just add the @Inject annotation to. The is pretty much all there is too it. Guice is very simple and has a relatively small learning curve.

Here is a code snippet showing injection of a dependancy into a constructor:

@Inject
public TimeChecker(IClock clock) { ... }


And here is the Module to tell Guice which concrete implementation to use:

@Inject
public TimeChecker(IClock clock) { ... }


Now to get an instance of TimeChecker you no longer need to build it's dependancies:

TimeChecker timeChecker = Guice.createInjector(new ProductionSettingsModule()).getInstance(TimeChecker.class);


For one dependency this looks like a lot of work, but if your class has four or five dependencies the above line does not get any bigger.