Testing on the Server

To let our tests loose on single units (e.g., the servlet class itself) we need mechanisms to get hold of the parameter objects used there. The most important ones are the request (HttpServletRequest), the response (Http-ServletResponse), and the configuration (ServletConfig). Cactus has been developed with the idea of automatic testing in mind; it offers a packaged and simple mechanism to automate server-side testing. Cactus is part of Apache's Jakarta project and extends JUnit by the ability to interface to servlet and JSP requests for a Web server. This means that we can manipulate the request object before a request and study the response object after the request's processing. Cactus can be downloaded from [URL:Cactus], including full documentation and installation instructions. Let's see the basic approach by our above servlet example. Note that Cactus test cases run both on the client and the server. This particular kind of split personality is shown in Screenshot and works like this:

Java Click To expand
Screenshot: Test case running in Cactus.

A translation of the above testGetRequest() test case for Cactus (in Version 2.3) looks like this:

import org.apache.cactus.*;
public class MyServletCactusTest extends ServletTestCase {
 public MyServletCactusTest(String name) {...}
 public void beginGetRequest(WebRequest theRequest) {
 theRequest.addParameter("name", "Johannes");
 public void testGetRequest() throws Exception {
 MyServlet servlet = new MyServlet();
 servlet.doGet(request, response);
 public void endGetRequest(WebResponse response) { connection =
 assertEquals("text/html", connection.getContentType());
 Johannes!") != -1);

The principle is as follows: First, the method beginGetRequest() is executed on the client. The request object can be prepared in this method (e.g., by setting a parameter). The request is then sent to the server, where it is intercepted by a proxy. This proxy causes the method testGet-Request() to be invoked, where the servlet is instantiated, initialized, and doGet() is invoked. In our earlier example, we could also test for the session state. Once the response is returned to the client, the endGetRequest() method is invoked on the client; it has access to the response object and HttpURLConnection.

The WebResponse class of Cactus does not offer the same comfort as the WebResponse class of HttpUnit to check the returned page for correct structure. But we can use the HttpURLConnection object to instantiate an Http-Unit WebResponse so that there is a rudimentary way to integrate Cactus and HttpUnit:

public void endGetRequest(WebResponse response) throws Exception { connection =
 com.meterware.httpunit.WebResponse httpUnitResponse =
 assertEquals("My Servlet", httpUnitResponse.getTitle());
 "Hello, Johannes!") != -1);
 com.meterware.httpunit.WebForm form =
 assertEquals("Johannes", form.getParameterValue("name"));
 assertEquals("Change Name",

Note that this example does not show the full set of functions available in Cactus. For example, we can access all methods of a servlet as well as the session object, cookies, and much more. In addition, Cactus supports Java server pages and the testing of JSP tag libraries. The package includes extensive documentation and many examples. Using Cactus to test Web apps has two main drawbacks. First, the app under test has to be deployed on an app server. This is time-consuming and slows down the testing-coding-testing cycle, similar to EJBs. Second, the test granularity is not as fine as we would like it to be for test-first development, because the starting point is always a servlet (or a JSP).

The major benefit of Cactus is that the Web component is checked for proper functioning on a real app server. Unlike HttpUnit, using Cactus means that we are no longer acting on the level of functional blackbox tests, but are actually running white-box integration tests.