September 21, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Test-Driven Development for Servlets

  • January 13, 2005
  • By Thomas Hammell
  • Send Email »
  • More Articles »

Test-Driven Development (TDD) is a practical way to produce better code faster. Although the ideas of TDD are easy to understand, its application in the real world requires not only the understanding of the concepts of TDD but also a good knowledge of certain tools needed to run the tests, proper setup of the development environment, and an understanding of how to use the tests to improve the design of the software.

The concepts of TDD are easy to understand and consist of three basic steps.

  1. Write a test that defines how you think a small part of the software should behave.
  2. Make the test run as easily and quickly as you can. Don't be concerned about the design of code; just get it to work.
  3. Clean up the code. Now that the code is working correctly, take a step back and refactor it to remove any duplication or any other problems that were introduced to get the test to run.

Using TDD to develop regular Java code is fairly straightforward and has been well explained in numerous articles and books. By using the JUnit (http://www.junit.org) framework and a mock object framework such as EasyMock (http://www.easymock.org), it is easy to develop your code, in isolation, in a simple incremental way.

Testing Servlet Code

Servlets are much harder to develop using TDD because servlet code requires a container to run; this is harder to simulate. There are a number of ways that you can test servlets as you develop them:

  • Use mock objects to simulate the parts of the servlet container needed by the servlets being developed.
  • Use a real servlet container and develop the servlet and JSP using in-container testing.
  • Use an already developed simulated servlet container such as Mockrunner or ServletUnit.

Using mock objects to simulate the servlet container is not really a good idea because simulating the entire container would be a very complex task and, if you don't simulate it correctly, when you deploy your servlets in a real container you may find additional problems that should have been caught in testing.

On the other hand, using in-container testing to test servlets also has its problems. To use in-container testing to run the tests inside the container, you have to deploy the application to a real Web or application server and then write some code to exercise the servlet. This would work, but would take a lot of effort.

You could reduce the effort it would take by using a testing framework such as Cactus (http://jakarta.apache.org/cactus) that provides an easy way to run tests inside the container of any application server. Cactus is a good framework and has a lot of support in the Java community, but it has some disadvantages. The main disadvantage is the overhead and complexity that Cactus adds to the process. To run tests using Cactus, you first have to package your application like you would if you were deploying it to a real J2EE application server, which means putting the servlets in a war file with the corresponding web.xml file.

Cactus also requires some configuration to run the tests. Setting up Cactus is not hard, but it is an extra step in the development process. All this extra overhead adds time to the test-code cycle and makes it harder to make changes to the code and quickly see the results.

Although in-container testing with tools, like Cactus, is a good idea and should be done as part of the development process, there is an easier way to test servlets using a simulate servlet container. Simulated servlet containers such as the ones provided by ServletUnit(http://www.httpunit.org) or Mockrunner(http://mockrunner.sourceforge.net) enable developers to test servlets without the overhead of in-container tests or the complexity of having to mock out all the methods of the servlet container. These tools are relatively easy to use and don't require a lot of overhead.

The only drawback to using a simulated servlet container for testing servlets is that when the servlet is deployed to the real container, it may show some problems that were not caught in the tests because the simulated servlet container works slightly differently than the real one. For the most part, though, this is not a problem and the simulated servlet container is the best way to start developing servlets because of its low overhead and simplicity; it provides the easiest solution to the problem of testing servlets. This is the TDD way, because one of the goals of TDD is to keep the tests as simple as possible. As your project progresses, you may need to use in-container testing to fully test all aspects of the servlets; but, for the most part, the simulated servlet container will allow you to quickly develop servlets using TDD.

To illustrate how to develop a servlet using a simulate servlet container, you can go through a simple example and learn how the process works. For the example, you are going to develop the servlet code needed to get the set of games for the weekly football pool. For this example, you will use the ServletUnit framework to simulate the servlet container. Before you start the example, take a look at the ServletUnit framework so you can understand how to use it in the example.

Servlet Unit Overview

ServletUnit is part of the HttpUnit framework and can be used to test servlets without a servlet container. ServletUnit allows you to not only execute a servlet and verify the results; it also allows you to individually test all its methods. ServletUnit includes a simulated servlet container that provides all the functionality of a real servlet container. This means that tests are very quick and easy to set up and run. To test a servlet using ServletUnit, you would have to perform the following steps:

  1. Create an instance of the ServletRunner class. This is the class that simulates the servlet container and allows access to the internal object's servlets being run.
  2. Register the servlet(s) that you plan to test with the ServletRunner.
  3. Create a ServletUnitClient. This client will enable you to access the different parts of the registered servlets.
  4. Create a WebRequest that is used to call your servlet. (Note: ServletUnit does not really use the host or port part of the URL of the WebRequest and only uses the part of the URL starting with the path.)
  5. Get the InvocationContext. The InvocationContext represents the invocation of a servlet. This interface enables you to access the servlet as well as its request and response objects.

Once you have the InvocationContext, you can get a handle to the servlet and execute any of its methods. This enables you to test the servlet a little piece at a time instead of testing just the final result.

Using ServletUnit enables you to develop servlets the TDD way, because it provides a means to test small parts of a servlet as it is being developed. For more detailed information on ServletUnit, see the HttpUnit site at http://httpunit.org.

PlayerPicksServlet Example

Now that we understand how to test a servlet let's start the example (The full set of source code can be downloaded here). Unzip the files from both downloads into one directory. Using TDD, of course, you start the development by writing a test. The test you write should test the behavior that you need to implement. For this example, you are not going to worry about how the servlet is called or how the data from the servlet will be displayed; you are just going to concentrate on implementing the desired behavior. The behavior that you want to implement is pretty simple; you want to create a servlet that can get a list of games for the weekly football pool. From this behavior, you write a normal JUnit test with the following test method.

public void testDisplayPlayerPicks()
   {
      // Set up ServletUnit to run the PlayerPickServlet
      ServletRunner sr = new ServletRunner();
      sr.registerServlet("PlayerPickServlet",
                         PlayerPickServlet.class.getName());
      ServletUnitClient sc = sr.newClient();
      WebRequest request =
         new PostMethodWebRequest("http://localhost/PlayerPickServlet");
      try
      {
         // Use the InvocationContext to create an instance
         // of the servlet
         InvocationContext ic = sc.newInvocation(request);
         PlayerPickServlet ppickServlet = (PlayerPickServlet)
                                          ic.getServlet();
         assertNull("A session already exists",
                    ic.getRequest().getSession(false));
         HttpServletRequest ppickServletRequest = ic.getRequest();

         // Call the servlets getOpenPool() method
         FootballPool openPool =
            ppickServlet.getOpenPool(ppickServletRequest);

         // Check the return football pool to make sure it is correct
         assertEquals("Kansas City", openPool.getAwayTeam(0));
         assertEquals("Green Bay", openPool.getHomeTeam(0));
         assertEquals("Houston", openPool.getAwayTeam(1));
         assertEquals("Tennessee", openPool.getHomeTeam(1));
         assertEquals("Carolina", openPool.getAwayTeam(2));
         assertEquals("Indianapolis", openPool.getHomeTeam(2));
         assertEquals("NY Giants", openPool.getAwayTeam(3));
         assertEquals("New England", openPool.getHomeTeam(3));
         assertEquals("Chicago", openPool.getAwayTeam(4));
         assertEquals("New Orleans", openPool.getHomeTeam(4));
         assertEquals("Oakland", openPool.getAwayTeam(5));
         assertEquals("Cleveland", openPool.getHomeTeam(5));
         assertEquals("Philadelphia", openPool.getAwayTeam(6));
         assertEquals("Dallas", openPool.getHomeTeam(6));
         assertEquals("Tampa Bay", openPool.getAwayTeam(7));
         assertEquals("Washington", openPool.getHomeTeam(7));
         assertEquals("Miami", openPool.getAwayTeam(8));
         assertEquals("Jacksonville", openPool.getHomeTeam(8));
         assertEquals("Pittsburgh", openPool.getAwayTeam(9));
         assertEquals("Denver", openPool.getHomeTeam(9));
         assertEquals("Buffalo", openPool.getAwayTeam(10));
         assertEquals("NY Jets", openPool.getHomeTeam(10));
         assertEquals("Baltimore", openPool.getAwayTeam(11));
         assertEquals("Arizona", openPool.getHomeTeam(11));
         assertEquals("San Francisco", openPool.getAwayTeam(12));
         assertEquals("Seattle", openPool.getHomeTeam(12));
         assertEquals("Atlanta", openPool.getAwayTeam(13));
         assertEquals("St. Louis", openPool.getHomeTeam(13));

      }
      catch (Exception e)
      {
         fail("Error testing DisplayPlayerPickServlet Exception
               is " + e);
         e.printStackTrace();
      }
   }

Listing 1: Test for getting a list of the weekly football games





Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel