Monthly Archives: October 2009

Testing Servlets with Mockito

When I write Java-projects that produce web pages, I test on several levels. First, I use Jetty and WebDriver to test the result via http. (WebDriver even lets me test JavaScript!)

But for speed and agility, unit-level tests beat even the fastest integration level tests. Unit tests run much much faster, and lets me pinpoint problems much more accurately. As a general rule: If you introduce a bug, you want a unit test to be the one that sees it first.

For web applications in Java, I’ve found the following pattern useful when testing classes that deal with HttpServletRequest and HttpServletResponse:

@Test
public void shouldDecodeSearchParameters() throws IOException {
    HttpServletRequest req = mock(HttpServletRequest.class);
    HttpServletResponse resp = mock(HttpServletResponse.class);
    Repository repository = mock(Repository.class);
 
    PersonController personController =
            new PersonController(req, resp, repository);
 
    given(req.getParameter("firstName")).willReturn("johannes");
    given(req.getParameter("lastName")).willReturn("brodwall");
    given(req.getParameter("includePaidMembers"))
            .willReturn("true");
    given(req.getParameter("includeUnpaidMembers"))
            .willReturn("false");
    when(resp.getWriter())
            .thenReturn(new PrintWriter(new StringWriter()));
 
    personController.find();
 
    ArgumentCaptor< PersonSpecification> specificationCapture = 
            ArgumentCaptor.forClass(PersonSpecification.class);
    verify(repository).find(specificationCapture.capture());
 
    PersonSpecification personSpec =
            specificationCapture.getValue();
    assertThat(personSpec.getFirstName()).isEqualTo("johannes");
    assertThat(personSpec.getLastName()).isEqualTo("brodwall");
    assertThat(personSpec.isIncludingPaidMembers())
         .isEqualTo(true);
    assertThat(personSpec.isIncludingUnpaidMembers())
         .isEqualTo(false);
}

1: This example uses Mockito to specify what calls to HttpServletRequest should return. A really nice thing about Mockito is that you only have to specify what you care about. If, for example, PersonController ends up calling req.getParameter("nonexistant"), Mockito will simply return null. If PersonContoller asks for “lastName” several times, Mockito will keep returning “brodwall”.

2: Mockito doesn’t verify that a set of methods were called unless you explicitly ask it to. PersonController happens to call several methods on HttpServletResponse that we don’t even mention in the test.

3: Mockito lets you look at what arguments were used to call a mocked-out method after the method was called by using an ArgumentCaptor.

One caveat, though: In the case of HttpServletRequest, the production code can decide to read the request parameters in several different ways: getParameter, getParameterValues or getParameterMap. Mockito will naturally not have any idea of the relationship between these methods, so your test will be sensitive to this sort of implementation change.

After working with EasyMock and JMock for a while, I seriously lost faith in mocking. Mockito has restored my faith again!

Happy testing!

Posted in English, Java | 3 Comments

Staggering toward the project goal

I’m working on a collection of patterns for early releases with Niklas Bjørnerstedt. Here are some of my thoughts based on this work.

In a few different projects, I’ve noticed that the idea of “where are we going” seems to go though a familiar pattern:

  1. “The old system is the requirement document, just make the new one do the same things”. After a while, someone will realize that it’s rather pointless to replace a system with a new one that does the same thing, which leads to…
  2. “Analyze the business processes and make the new system automate all decisions that a human used to make.” After a while, people start realizing that business rules are interpreted slightly different by different users and finding a consensus approach is hard. Besides, some of the decisions require human judgment. On top of this, progress towards implementing the business processes is much slower than expected. As a matter of fact, people are panicking as the project gets increasingly delayed, which leads to…
  3. “Just do whatever the old system did, with whatever improvements are dead easy. Just get this damned thing out the door.” Even reducing the scope to just the “bare bones of the current system with minimal improvements” doesn’t seem to give sufficient progress. Or sufficient value to justify the project. So, finally, we arrive at…
  4. “Can we just add a new piece of software that makes an existing business process easier. And repeat until the budget is spent.”

The sad conclusion is that the original goal of replacing the old system begins to appear further into the future. At the same time, the new system will realize some value to some stakeholder pretty soon thereafter. Maybe the first step towards a successful replacement project is giving up replacing the old system?

The good news is that with an iterative approach to the requirement process, my current project was able to go through all these steps in a couple of months. Which beats my previous record of a year of full burn rate in stage 1.

Posted in Agile Release Patterns, English, Extreme Programming, Software Development | 3 Comments