Sunday, August 19, 2007

Unit Testing jsp:include

If you're stuck with some JSPs and need to test them with MockRunner, you'll eventually run in the problem to test jsp:include. MockRunner doesn't come with built-in support for this, but this itch can be scratched with a few lines of code:

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;

import com.mockrunner.mock.web.MockRequestDispatcher;
import com.mockrunner.servlet.ServletTestModule;

/**
 * Allow to use jsp:include in tests.
 */
public class NestedMockRequestDispatcher extends MockRequestDispatcher
{
    public ServletTestModule servletTestModule;
    public HttpServlet servlet;

    public NestedMockRequestDispatcher (
            ServletTestModule servletTestModule,
            Class servletClass)
    {
        this.servletTestModule = servletTestModule;
        servlet = servletTestModule.createServlet(servletClass);
    }

    @Override
    public void include (ServletRequest request, ServletResponse response)
            throws ServletException, IOException
    {
        servlet.service(request, response);
    }
}

In your test case, add this method:

    public void prepareInclude(Class servletClass, String path)
    {
        NestedMockRequestDispatcher rd = new NestedMockRequestDispatcher (createServletTestModule(), servletClass);

        getMockRequest().setRequestDispatcher(path, rd);
    }

The path is absolute but without the servlet context. So if the included JSP is named "foo.jsp" and the context is "/webapp", then path is "/foo.jsp". If that doesn't work, print the result of getMockRequest().getRequestDispatcherMap() after the test and you'll see the paths which are expected.

All that's left is to call this method in setUp() for all JSPs that you need to test. If you forget one, the jsp:include just won't do anything (i.e. you won't get an error). To make sure you don't miss any includes (especially ones which you lazy co-workers added after you wrote the test), I suggest that you check the map after the test run for entries which aren't instances of NestedMockRequestDispatcher.

No comments: