Wednesday, June 13th, 2007

Introduction to HttpUnit

In today’s application development environment it is standard practice to build unit tests for each object being developed. Unit testing is increasingly more and more popular in Java due to the many open-source unit testing frameworks available. However, this type of testing becomes more difficult when the application is Web based or contains EJBs because of the dependency on application servers, servlet containers and EJB containers. We can, though, test the publicly exposed portion of the Web application with frameworks like HttpUnit.

HttpUnit is a Java testing framework, which is used to access Web-based content in a manor similar to that of a Web Browser. Most things a user can do through a Web browser can be emulated with HttpUnit. It even supports form submission, JavaScript to a degree, and https. Additionally, HttpUnit allows one to examine the returned pages.

Let’s examine a very simple HttpUnit example by testing one of my favorite sites, http://carcruises.com. This site lists a considerable amount of car cruises within the US by month and state passed to the server in the form of query parameters. We want to test the results of querying for a list of cruises in Pennsylvania for the month of June.

First, we must create a class to extend the junit.framework.TestCase class. This is necessary to take advantage of JUnit’s assert methods. Within this class we create a test method (testGetPAJuneCarcruises) where we will emulate an http call to the car cruises website.

Listing 1
public class CarCruisesTest  extends junit.framework.TestCase {
    public void testGetPAJuneCarcruises() {
        String sURL = “http://carcruises.com/” +
            “cruise_list.asp?month_select=6&” +
            “state=Pennsylvania”;
        try {
            // Create the conversation object,
            // which will maintain state for us
            WebConversation conversation = new WebConversation();
            WebRequest request = new GetMethodWebRequest(sURL);
            WebResponse response = conversation.getResponse(request);
        } catch (Exception ex) {
            ex.printStackTrace();
            // Fail the test if an exception is thrown.
            super.fail(ex.getMessage());
        }
    }
}

Listing 1 illustrates 3 significant lines of code. Initially we must instantiate a WebConversation object. This object is responsible for maintaining the session of the connection just like a Web Browser does when a human is looking at the URL. Next, we must create a WebRequest object pointing to the URL. This object can be a “GET”, “PUT” or “POST” request. Finally, we create a WebResponse object used to retrieve the results of the request.

OK, so that was easy enough but we haven’t tested anything. Usually it is standard practice to invoke JUnit assertNotNull methods on each of the objects (which is why our class must extend junit.framework.TestCase). Therefore, after instantiation of each object perform an assertNotNull as illustrated in Listing 2. If any of the objects are null the test will fail before moving on to the instantiation of the next object.

Listing 2
public void testGetPAJuneCarcruises(){
        String sURL = “http://carcruises.com/” +
            “cruise_list.asp?month_select=6&” +
            “state=Pennsylvania”;
    try {
        // Create the conversation object,
        // which will maintain state for us
        WebConversation conversation = new WebConversation();
        assertNotNull(”New conversation”, conversation);
        WebRequest request = new GetMethodWebRequest(sURL);
        assertNotNull(”Request to URL “+sURL,request);
        WebResponse response = conversation.getResponse(request);
        assertNotNull(”Response from URL ” + sURL,response);
    } catch (Exception ex) {
        ex.printStackTrace();
        // Fail the test if an exception is thrown.
        super.fail(ex.getMessage());
    }
}

If all of our objects are not NULL then we are ready to take a closer look at the WebResponse object. We’ll want to test for a valid response code by using the WebResponse object’s getResponseCode. If this method returns a 200 then we can test for other response objects. For example, we can test that the response message returns “OK” by making a call to the WebResponse object’s getResponseMessage method. Typically responses from Web applications also contain titles. We can test for a title by performing an assertEquals using the WebResponse object’s getTitle method. Snippet 1 illustrated these three tests.

Snippet 1
assertEquals(”Response code should return 200″,
    200, response.getResponseCode());
assertEquals(”Response message should return OK”,
    “OK”,response.getResponseMessage());
assertEquals(”Car Cruises Online - Cruise Listing”,
    response.getTitle());

If theses assertions are correct we can begin to look at forms and links. Snippet 2 demonstrates the methods necessary to retrieve this data from the WebResponse object. Since more than one form or link can be present in any one response, the methods return arrays of type WebForm and WebLink respectively. For our example we know there is only one form in the response so we first test for NULL then we test the array length to make sure we only received 1 form. As for links, our example is using a dynamic URL in which the number of links can change at any time. Therefore we just test for null and then to be consistent we check the array length to make sure it is greater than or equal to 0.

Snippet 2
WebForm[] forms = response.getForms();
assertNotNull(forms);
assertTrue(”Response should contain only 1 form”,forms.length == 1);
WebLink[] links = response.getLinks();
assertNotNull(links);
assertTrue(”Response should contain 0 or more links”,links.length >= 0);

Each of the WebForm and WebLink objects can be further broken down into other objects. Each URL may or may not utilize this inner objects. Some of these objects are Buttons, Methods, Parameters, and so on. Likewise, the WebResponse object can be further broken down into other objects. Please see the HttpUnit javadocs for more information (http://httpunit.sourceforge.net/doc/api/index.html).

Another interesting thing to note is that usually one would disable HttpUnit from throwing exceptions due to JavaScript errors. This is necessary because of the on-going differences in the inner workings of JavaScript. Therefore, as a first step, use Snippet 3 to disable these exceptions before the instantiation of the WebConversation object

Snippet 3
// Don’t let JavaScript errors trip us up!
HttpUnitOptions.setExceptionsThrownOnScriptError(false);

Putting it all together we create the code in Listing 3. Usually I do all of my development work in Eclipse so I can execute any JUnit test directly from the IDE, however, it can also be executed through ant if so desired. Snippet 4 illustrates a simple ant task that will execute any Junit test classes whose source code is in the relative directory src/java.test and whose name ends with Test.java. This also assumes you’ve already compiled your test source files and they are included in the test.classpath path.

Listing 3
public class CarCruisesTest  extends junit.framework.TestCase{
    public void testGetPAJuneCarcruises(){
        String sURL = “http://carcruises.com/” +
            “cruise_list.asp?month_select=6&” +
            “state=Pennsylvania”;
        try {
            // Don’t let Javascript errors trip us up!
            HttpUnitOptions.setExceptionsThrownOnScriptError(false);
            // Create the conversation object which will maintain
            // state for us.
            WebConversation conversation = new WebConversation();

            // Create the request object pointing to our URL.
            WebRequest request = new GetMethodWebRequest(sURL);

            // Perform a get request and store results in response.
            WebResponse response = conversation.getResponse(request);

            // Check for valid response code.
            assertEquals(”Response code should return 200″,
                        200,response.getResponseCode());

            // Check for valid response message.
            assertEquals(”Response message should return OK”,
                        “OK”,response.getResponseMessage());

            // Check for valid response title.
            assertEquals(”Car Cruises Online - Cruise Listing”,
                        response.getTitle());

            // Make sure there is 1 and only 1 form.
            WebForm[] forms = response.getForms();
            assertNotNull(forms);
            assertTrue(”Response should contain only 1 form”,
                        forms.length == 1);

            // Make sure the Links are not NULL.
            WebLink[] links = response.getLinks();
            assertNotNull(links);
            assertTrue(”Response should contain at least 1 link”,
                        links.length >= 1);
        } catch (Exception ex) {
            ex.printStackTrace();
            // Fail the test if an exception is thrown.
            super.fail(ex.getMessage());
        }
    }
}

Since we instruct Junit to format the output as xml we can then feed the resultant xml into the JunitReport task and generate html to make the results pretty. For further information on these ant task please see the JUnit project at sourceforge.

Snippet 4
<target name=”test” >
	<mkdir dir=”tst-rslts”/>
	<junit haltonfailure=”no” printsummary=”yes”>
		<classpath refid=”test.classpath”/>
		<batchtest fork=”yes” todir=”tst-rslts”>
			<formatter type=”xml”/>
			<fileset dir=”src/java.test”>
				<include name=”**/*Test.java”/>
			</fileset>
		</batchtest>
	</junit>
	<junitreport todir=”tst-rslts”>
		<fileset dir=”tst-rslts”>
			<include name=”TEST-*.xml”/>
		</fileset>
		<report format=”frames” todir=”tst-rslts”/>
	</junitreport>
</target>

» Filed under Tutorials, Articles by Larry Liberto at 21:28.

Leave a comment





Credits

All content copyright (c) 2003-2007 createTank, llc