Tapestry Unit Testing

One of the many appeals of Tapestry is that it’s a lot easier to unit test Tapestry pages than, say, anything involving JSPs. In general, JSPs can only be tested in a servlet container because the JSP needs to be compiled into code.

Certainly, tools like HTTPUnit can make that easier, but I’ve never been fond of having to deploy to the server any time I want to run my unit test suite.

Because Tapestry doesn’t use JSPs, I can more easily test my individual page classes, and ensure that the page class is correctly implemented.

Testing web assets of any sort requires some mock implementations of the standard javax.servlet interfaces. Intelliware created a set of mock implementations several years ago, and we have reused them again and again.

Initializing Tapestry in the Unit Test

To test a Tapestry page, we first need to initialize the Tapestry ApplicationServlet the same way that a real servlet container would.

protected MockServletContext initializeServlet(
    String name, HttpServlet servlet) throws ServletException {
  MockServletContext context = new MockServletContext();
  context.setWebRootDirectory(new File("../myWebProject/WebRoot/"));

  MockServletConfig config = new MockServletConfig(name, context);
  servlet.init(config);
  return context;
}

The ApplicationServlet needs to know where to find the base HTML files and *.page files, so we set up a web root directory. Also, Tapestry uses the servlet name to configure itself.

Sending Mock Requests

Next, we want to run a test of a particular page.

public void testDisplay() throws Exception {

  ApplicationServlet servlet = new ApplicationServlet();
  initializeServlet("myapp", servlet);

  MockHttpServletRequest request = new MockHttpServletRequest(
      "http://localhost:8080/myapp/index.html");
  request.setServletPath("/index.html");

  MockHttpServletResponse response = new MockHttpServletResponse();

  servlet.service(request, response);

  assertEquals("status", HttpServletResponse.SC_OK,
      response.getStatus());
...

There are a few interesting parts of this test. First, we initialize the servlet, as we described above. Next, we create a mock request. One thing to note in this test is that we used a “friendly URL patch” for Tapestry, so that we’d have URLs that look like typical web sites.

Assertions

Next, we can test that Tapestry has produced the correct output. Suppose we have an area of our page that shows today’s date. We can scan the response looking for that piece of data.

Here’s a relatively straight-forward way of doing that:

\  SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
  String output = new String(response.getOutputStreamContents());
  String currentDate = formatter.format(new Date());
  assertTrue("date", output.indexOf(currentDate) >= 0);

Unfortunately, it’s not a very precise test.

If we use some HTML parsing tools, we can make some more specific test cases. I use some utilities derived from JTidy to make my life easier.

Suppose the date that I’m looking for exists in an identified HTML tag, such as a span:

<span id="currentDate">2005-07-30</span>

Then we can find the element, and check that it contains the correct date.

\  Node root = parseResponseUsingJTidy(response);

  Node span = NodeUtil.getElementById(root, "currentDate");
  assertNotNull("currentDate", span);
  assertTextNodeEquals("currentDate text", currentDate, span);

Being able to unit test Tapestry assets is one of the many things that makes the framework so attractive.

It's only fair to share...
Share on FacebookGoogle+Tweet about this on TwitterShare on LinkedIn

Leave a Reply