Using EasyMock to enable response text based testing of Java Servlets

entrada antigua del 23/3/2011 – old post from 3/23/2011

—–

Behind this long title, today I would like to show an easy but powerful technique to unit test Java Servlets.

This method focuses in the fact that most of the Java Servlets are just returning plain text contents, usually HTML or XML.

For a proper unit test on the Java Servlet to run outside a web container, we need to mock the HttpServletRequest and HttpServletResponse objects. Mock, in short, is a term to refer to a double object, that is, an object that exists solely for the purpose of testing the unit at hand, with the same interface that an actual runtime object but with a different behavior, based on expectations.

It is not the purpose of this post to talk about mocks and other unit testing techniques. If you feel curious you can get more on the subject on this excellent paper from Martin Fowler (yes, ‘that’ Fowler guy): Mocks aren’t Stubs, by Martin Fowler.

With that being said, let’s go to the point. What we want to achieve is to test the output of a Java Servlet in different situations, asserting that this output contains certain strings of text. We will need to mock the request and response objects.

For the request object we will instruct that when asked for certain parameters some fixed values will be returned. Those fixed values will imply a different output that we would like to assert.

For the response object we will instruct a new behavior: when asked for the PrintWriter object (the one used to print contents to the output) the mock will return a writer linked to a temporary file just created in the test code.

Then, all we would need to do is to check the temporary file contents for specific strings of text. Nice, eh?

Putting it all together, the code will look like this:

import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.junit.Test;

import sdc.commons.io.IOToolkit;

public class SchedulerServletTestCase {

    public SchedulerServletTestCase() {
        super();
    }

    @Test
    public void testServletResponseInitialized ()
        throws NoSuchMethodException, InvocationTargetException,
               IllegalAccessException, IOException {

        HttpServletRequest request = createNiceMock(HttpServletRequest.class);
        expect(request.getParameter("mode")).andReturn("init");

        HttpServletResponse response = createNiceMock(HttpServletResponse.class);
        File temp = File.createTempFile("sdc", "test");
        temp.deleteOnExit();
        expect(response.getWriter()).andReturn(new PrintWriter(temp));

        replay(request);
        replay(response);

        SchedulerServlet ss = new SchedulerServlet();
        ss.doGet(request, response);

        verify(request);
        verify(response);

        byte[] output = IOToolkit.readFile(temp);
        String s = new String(output);

        assertTrue(s.contains("<title>Scheduler Command Center</title>"));
        assertTrue(s.contains("<b>Initializing Scheduler</b><br/>"));
    }

    @Test
    public void testServletResponseNotInitialized ()
        throws NoSuchMethodException, InvocationTargetException,
               IllegalAccessException, IOException {

        HttpServletRequest request = createNiceMock(HttpServletRequest.class);
        expect(request.getParameter("mode")).andReturn("stop");

        HttpServletResponse response = createNiceMock(HttpServletResponse.class);
        File temp = File.createTempFile("sdc", "test");
        temp.deleteOnExit();
        expect(response.getWriter()).andReturn(new PrintWriter(temp));

        replay(request);
        replay(response);

        SchedulerServlet ss = new SchedulerServlet();
        ss.doGet(request, response);

        verify(request);
        verify(response);

        byte[] output = IOToolkit.readFile(temp);
        String s = new String(output);

        assertTrue(s.contains("<title>Scheduler Command Center</title>"));
        assertTrue(s.contains("<b>Stopping Scheduler</b><br/>"));
    }
}

Some explanation to the test code:

  • A ‘nice’ mock is one that returns sensible defaults (0, false, null) to the mocked methods, unless an expectation is defined. It does not enforce any particular methods to be executed during the test, or in any particular order.
  • The replay static method of EasyMock means that we have finished the definition of expectations and the actual test begins.
  • The verify static method of EasyMock is used after the test to review the method execution status. We are running with nice mocks so this is not so much useful, but it is a good practice to write it always so you do not forget when you really need it.
  • The IOToolkit class is just a helper class that we use to read the file and put the contents in an array of bytes. Just easy to proceed looking at the contents.
  • The temp file is deleted automatically by the VM, so you don’t need to take care of it.

You can imagine that the actual test code was more complex than this, with more parameters involved, also internal servlet status, plus a lot of assertions more. But the point is that the base technique is the same, easy to apply and easy to repeat throughout your existing servlets.

Hope this helps in your daily work. And please, don’t forget that anytime a Servlet is not unit tested, a request is killed!

Author: deors

senior technology architect in accenture, with a passion for technology related stuff, celtic music and the best sci-fi, among other thousand things!

1 thought on “Using EasyMock to enable response text based testing of Java Servlets”

  1. Lovely piece of work. I transposed it into a test but sadly, nothing gets written into the temporary file, even though everythings seems to run smoothly😦

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s