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());
}
}

2 comments:

Roger Pack said...

how does this apply for newer junit, perchance?

Steve Asher said...

Roger, I think that this is out of date now. I'm not quite sure how though. I've been using Mockito lately.

You should try it out and let us know.