The Weak Reference

The Weak Reference

Kurser i Domain-Driven Design - VĂ¥ren 2012




Tuesday, October 06, 2009

Mocking to the Rescue!

I am not really a big fan of mocking. My experience is that if you design your code to be testable, you only rarely have to rely on mocks, instead you'll be fine just by stubbing an interface or two. But even as a proponent of what Martin Fowler calls classic TDD, I find it there are times when a mocking tool can come in handy. One situation is when you have to work with API:s that lack good interfaces, in these cases a good mocking tool with support for mocking concrete classes can be of great help.

Mockito is what I would like to consider a next-generation mocking tool, with support for both mocking and stubbing. Mockito fully and naturally uses recent language enhancements in Java, such as generics, static imports and annotations, to make the tool easy to use. Writing clean and elegant test code that is easy to understand can actually be pretty simple. TheMockito API is straightforward and well designed, the need for infrastructure code is kept to a minimum. If you are an EasyMock user, this comparison may be helpful when following along in the code below: http://code.google.com/p/mockito/wiki/MockitoVSEasyMock

Let's look at a few examples!

Stub an interface

A nice property of systems built using dependency injection is that you get loosely coupled systems with well-defined interfaces that are easy to stub for testing. It is easy enough to provide stub implementations of these interface directly in the test classes, e.g. as anonymous implementations or inner classes. But despite this, I have found myself more and more starting to rely on Mockito for these situations, it's fewer lines of code, and very convenient!
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;
import static org.junit.Assert.assertEquals;

[...]

ClientRepository repository = mock(ClientRepository.class);
ClientId clientId = new ClientId(123);
Client client = new Client(clientId, new Name("Test", "User"));
when(repository.findById(clientId)).thenReturn(client);
Now, as an example, we can use our ClientRepository instance to test a service class:
FancyService service = new FancyServiceImpl();
service.setRepository(repository);
assertEquals(client, service.findClientAndDoSomethingTrulyAwesome(123));
When stubbing like this we are usually not that interested in verifying behaviour of the stub. But if we, for some reason, would like to explicitly make sure that the method findById(...) was called, we can do this with the following line of code:
verify(repository).findById(clientId);

Stubbing concrete classes

Now and then you encounter API:s that were not as designed for testing that you could wish for. In these cases, the possibilities of stubbing concrete classes can be very helpful.

Restlet

Restlet is a Java framework for creating RESTful web service. Reslet consists of quite a big API, and the authors have, among other things, decide to create their own implementation of things like Request, Response, Status.SUCCESS_OK (HTTP response 200) etc. Unfortunately, many parts of the API consists of concrete classes, instead of interfaces. One downside of this is that it is sometimes hard to write tests for code that uses the Restlet APIs.

Stubbing the concrete class org.restlet.data.Response is easily done in the same way we stubbed the ClientRepository interface above:
import static org.mockito.Mockito.*;
import org.restlet.data.Response;
import org.restlet.data.Status;
import org.restlet.resource.Representation;

[...]

Response response = mock(Response.class);
Representation entity = mock(Representation.class);
when(response.getStatus()).thenReturn(Status.SUCCESS_OK);
when(response.getEntity()).thenReturn(entity);

Quartz

Quartz is a scheduling component that is supported and also used by many popular application development frameworks and application servers, including Spring and Seam. When using Quartz you define jobs that execute according to a schedule. Every time a job is triggered a new instance of the job class is created, and executed. If state is to be saved between job executions it has to be stored in some kind data structure outside of the job. Quartz makes a context available, org.quartz.JobExecutionContext, for this and other purposes. The context is handed to every newly created job instance. The context can, a bit simplified, be viewed as Map where the job can store and retrieve data.

If we would like to make data available to a job or read the result from a job execution we have to create an instance of JobExecutionContext and hand to our job. Creating this instance is however quite complicated, and since Quartz also tends to favor concrete classes over interfaces, it makes it hard for us to provide our own implementation. Fortunately, Mockito (or another mocking tool that can mock concrete classes) can help us out here as well!

Use Mockito to setup the context and set a fictional indexCount parameter as input value to the job:
import static org.mockito.Mockito.*;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;

[...]

JobExecutionContext ctx = mock(JobExecutionContext.class);
JobDetail detail = mock(JobDetail.class);
JobDataMap map = new JobDataMap();
map.put("indexCount", 145);
when(detail.getJobDataMap()).thenReturn(map);
when(ctx.getJobDetail()).thenReturn(detail);
Now we can use the context in our test:
IndexUpdaterJob job = new IndexUpdater();
job.execute(ctx);
And verify that the index was updated:
map = ctx.getJobDetail().getJobDataMap();
assertEquals(146, map.get("indexCount"));

Mocking

As the name suggests, Mockito can of course be used for different kinds of mocking as well. For more examples, have a look at the Mockito documentation.

No comments: