RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Build a Java Web App Using HttpUnit and the Test-driven Methodology, Part I : Page 5

The HttpUnit client API complements JUnit functionality to provide thorough Web testing capability. This first article of a two-part series breaks down how HttpUnit delivers these features and walks you through a step-by-step setup of a test-driven environment.

Write Your Tests, Classes, and JSPs
Now proceed to writing your tests and your Java classes and JSPs for the phone list application. Since you are testing first, write the test before writing the code to implement the functionality. That way, you can be more certain that your test works and that the functionality being tested works. In order to test, you need to have a basic idea of how your application will work. The phone list application will have two pages:
  1. A page that displays the list of contacts with basic properties for each contact (The show list page also allows you to choose a contact to edit or choose contacts to delete.)
  2. A page that lets you enter or edit the details for a contact

Write the test for the page that displays the list of contacts. The test should do a couple of things:

  1. Verify that the "display contacts" page exists and returns content
  2. Verify that the "display contacts" page shows either a message that there are no contacts in the list or the list of contacts in the system

Go to the ~/projects/phonelist/src/test/com/abcinc/phonelist/test directory and create a file called ShowListTest.java. Create the shell for the ShowListTest class. The ShowListTest class will initially look like this:

package com.abcinc.phonelist.test;

import junit.framework.TestCase;
import junit.framework.TestSuite;

public class ShowListTest extends TestCase {
  public static void main(String args[]) {

  public static TestSuite suite() {
    return new TestSuite(ShowListTest.class);

  public ShowListTest(String s) {

The class contains two methods and a constructor. The static main method allows you to run the class from the command line or via an Ant <java> target call, which you will need to do in order to perform the testing from within an Ant target. The static suite method instantiates a new TestSuite object, which is passed to the static run method of the TestRunner class. You can instantiate a TestSuite object either with a TestCase-derived class or without one. If you pass in an instance of a subclass of TestCase, the TestSuite constructor will scan the TestCase-derived class for methods whose names begin with "test" that accept no arguments. The TestSuite object will automatically run all of the matching methods in the TestCase-derived class.

Now add in the tests. Place the following method after the ShowListTest constructor:

  public void testShowList() throws Exception {
    WebConversation webConversation = new WebConversation();
    String url = protocol + "://" + hostname + ":" + port + path;
    WebRequest webRequest = new GetMethodWebRequest(url);
    WebResponse webResponse = webConversation.getResponse(webRequest);
    assertTrue("No content in phone list page", webResponse.getText().length() > 0);
    WebTable webTable = webResponse.getTableStartingWith("Phone List");
    assertNotNull("Phone List HTML table not found", webTable);
    assertTrue("Phone List table has less than 4 rows", webTable.getRowCount() >= 4);

The testShowList method performs the following actions:

  1. Issues an HTTP GET request to the server at the location specified by the String object named "url"
  2. Obtains the HTTP response and stores it in a variable
  3. Verifies that the response contains more than zero bytes of data
  4. Verifies that the response contains an HTML table that has "Phone List" as its first non-blank text
  5. Verifies that the HTML table starting with "Phone List" has at least three rows of data

In addition to the code for the testShowList method, you also need to add in some import statements so that the HttpUnit classes you use in testShowList are recognized. Add the following code above the two "import junit" lines:

import com.meterware.httpunit.GetMethodWebRequest;
import com.meterware.httpunit.TableCell;
import com.meterware.httpunit.WebConversation;
import com.meterware.httpunit.WebRequest;
import com.meterware.httpunit.WebResponse;
import com.meterware.httpunit.WebTable;

Also note that the testShowList method you just typed makes reference to a few variables that are not declared or defined: protocol, hostname, port, and path. So, add the following lines above the declaration of the main method but inside the ShowListTest class declaration:

  private static String protocol = "http";
  private static String hostname = "localhost";
  private static int port = 8080;
  private static String path = "/phonelist/showList.do";

Your ShowListTest.java file should now look like the ShowListTest.java.v1 file supplied in the example files archive. Compare them to verify. The ShowListTest.java.v1 file contains comments that may simplify your understanding of how to build a TestCase-derived class.

You have now written the ShowListTest class, but you will not be able to compile or run it yet because the build.xml file contains no instructions pertaining to the tests. Add those instructions now to build.xml. First, you need to define a property that specifies the location of the HttpUnit distribution directory so that you can access the JAR files containing the classes. Add the following to the build.xml file right after the line defining the struts.install.dir property, which is located in the "init" target definition:

    <property name="httpunit.install.dir" value="/home/wchao/packages/httpunit-1.5.4"/>

As usual, replace the value of the property with the location of the package on your system. Since you will be compiling Java classes that make use of the HttpUnit libraries, you will need to include the HttpUnit files in the classpath. Add the following lines to the build.xml file right after the line that says <property name="classpath" refid="base.path"/>:

    <path id="test.lib.path">
      <path refid="base.path"/>
      <fileset dir="${httpunit.install.dir}/lib">
        <include name="*.jar"/>
      <fileset dir="${httpunit.install.dir}/jars">
        <include name="*.jar"/>

    <property name="test.lib.classpath" refid="test.lib.path"/>

You will use the test.lib.classpath property later to provide access to the HttpUnit libraries during compilation of your test classes. Now, add the following target to build.xml right after the target called "compile-classes":

  <target name="compile-tests" depends="init, create-unpacked-layout-dirs">
    <mkdir dir="${build.dir}/test"/>
    <javac destdir="${build.dir}/test"
      <src path="${src.dir}/test"/>
      <classpath path="${test.lib.classpath}"/>

The compile-tests target compiles the test classes located in the src/test directory of the phonelist project. It makes use of the test.lib.classpath property you previously defined to enable the compiler to resolve references to the HttpUnit libraries.

You need some targets to run the tests. Add the following snippet of XML to the build.xml file right after the definition of the deploy target:

  <target name="test"
          depends="compile-tests, post-compile-tests-init, test-showlist"
          description="Run all tests"/>
  <target name="test-showlist" depends="compile-tests, post-compile-tests-init" description="Run showlist test">
    <java classname="com.abcinc.phonelist.test.ShowListTest">
      <classpath path="${test.complete.classpath}"/>

You define the test target so that you can run all tests with one command. You will have to keep adding to the depends attribute of the test target as you add more tests. The test-showlist target merely runs the showlist test. You may notice that the two targets you just defined rely on a target that does not yet exist as well as a property that does not yet exist. The non-existent target is post-compile-tests-init. The non-existent property is test.complete.classpath. In post-compile-tests-init, you define the test.complete.classpath property so that you can use it as a classpath in the test-showlist target. The reason you define the test.complete.classpath property separately in post-compile-tests-init rather than within the init target is that the test classes have not yet been compiled when the init target executes. Therefore, defining a path that included the test classes would not work because Ant expects path definitions to specify paths that exist. So add the post-compile-tests-init target. Add the following XML code to build.xml after the compile-tests target:

  <target name="post-compile-tests-init" depends="init">
    <path id="test.complete.path">
      <path refid="test.lib.path"/>
      <dirset dir="${build.dir}/test">
        <include name="**"/>
    <property name="test.complete.classpath" refid="test.complete.path"/>

At this point, your build.xml file provides sufficient information for Ant to perform a build of the Web application. You have also told Ant how to perform a build of the tests and to execute the tests. You can copy build.xml.v2 from the example code archive and use it as your build.xml file. It should be the same as the build.xml file you just created, but it will have helpful comments that were excluded from the walk-through.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date