Unit tests, mocking and DI in Java
I have recently been investigating dependency injection (DI) and unit testing using mock objects in Java. After browsing advice on Stack Overflow and trying out various frameworks, I have settled on my favourite stack:
- Dependency Injection: Guice. It was either Guice or Spring, but don’t want / need all the other stuff bundled with Spring. Nice and lightweight, and simple.
- Unit tests: JUnit. I chose this because Netbeans (my IDE of choice) has extensive integration with JUnit
- Mocking framework: EasyMock. As the name implies, it’s easy to use nad seems to be popular, and the documentation is clear
- AtUnit. This is a nice auto-mocker which integrates Guice with EasyMock, meaning much less code needs writing to set up tests with dependency injected mocks
I knew I had a good stack here because my first tests was easy and quick to write, readable and concise, requiring no base classes to write at all. For me, K.I.S.S. always wins - Keep It Simple Stupid!
After downloading the libraries and adding them to my project, I just needed to write one class:
import static org.easymock.EasyMock.*;
import atunit.AtUnit;
import atunit.Container;
import atunit.Mock;
import atunit.MockFramework;
import atunit.Unit;
import com.google.inject.Inject;
import components.utilities.ISecurityTask;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AtUnit.class)
@Container(Container.Option.GUICE)
@MockFramework(MockFramework.Option.EASYMOCK)
public class StartupTest
{
@Inject @Unit Startup startup;
@Mock ISecurityTask mockSecurityTask;
@Test
public void testStart() throws Exception
{
expect(mockSecurityTask.userIsAuthorised()).andReturn(true);
replay(mockSecurityTask);
startup.start();
verify(mockSecurityTask);
}
}
In this test I am testing my Startup class, which has a constructor dependency on ISecurityTask, testing to make sure that it calls userIsAuthorised() on ISecurityTask when startup() is called. To achive this I have:
- Told JUnit to use AtUnit as the test runner with @RunWith
- Told AtUnit that I am using Guice as theDI container with @container
- Told AtUnti I am using EasyMock with @MockFramework
- Mocked my ISecurityTask interface (you just need to annotate it with @mock and AtUnit will create a mock for it when you run your test) to decouple the concree implementation of ScurityTask from my test
- Declared my Startup class as the unit under test with @Unit
- Told Guice to inject starup with dependencies with @Inject. This is where the AtUnit magic happens: because I have declared a mock ISecurityTask, the mock will automatically by injected into Startup
- Set up an expectation on the mock security task for a call to its userIsAuthorised() method
- Called startup() on the Statrup class
Now I just need to right-click the test (or a test suite which includes the test) in NetBeans, and hit ‘Run’. I’ll look into running them using Ant later!
