Testing. For many of us developers, the word makes us cringe. This stigma about testing can probably be traced to the tedium of testing in the past. Fortunately, frameworks are now available to ease the testing burden. Today's high-pressure projects with project managers breathing down your neck with printouts of schedules from Microsoft Project is an environment that can breed errors in your code. Accordingly, thorough testing is more important than ever.
One testing framework that has gained a lot of acclaim recently is JUnit. Using JUnit, you can incrementally build test suites during your development process. Such automated unit testing is an integral part of Extreme Programming (XP) methodology. JUnit is fine for Java™ programmers, but what about those of us who do Web development? The open-source Java APIs of HttpUnit can come to our rescue. In this tutorial, we will build a small Web site with IBM® WebSphere® Studio Application Developer Version 5 (hereafter called Application Developer), then use HttpUnit to test our sample site. (A note on versions: while the steps and screen shots below apply to Version 5, you should encounter only slight differences in a few places if you are using Version 4.)
Traditional (Neanderthal) ways to test Web sites
I'll admit it -- in the past, I have created small "driver" pages with
forms to feed data to Java servlets that I am trying to test. I have also
manually tacked on name-value pairs to the end of URLs, such as
http://www.somesite.com/myPage?myVarName=myTestValue.
Both of these methods can work. However, they can be like trying to mow
your lawn with a pair of scissors. There has to be a better way.
Unlike with the test methodologies above, HttpUnit does not require you to use your browser. With HttpUnit, you can make direct calls to the code you are testing. HttpUnit in essence mimics a Web browser, and the HttpUnit API can emulate a number of browser behaviors, including:
- Form submission
- JavaScript
- HTTP authentication
- Cookies
You can also use the HttpUnit API to analyze the content returned when a Web page is loaded.
Why HttpUnit instead of the alternatives?
With the growth of the Web and the conspicuous nature of Web programming errors, many commercial test products hit the market with elaborate GUIs to guide the developer through the testing process. The open-source HttpUnit, on the other hand, is free of licensing fees and very simple to use (as you'll see below). It is this simplicity that makes it so popular. While it lacks a pretty GUI, the availability of the HttpUnit Java source code and its simple API let developers create their own testing solutions to fit for the needs of their particular organizations. Using HttpUnit as a foundation, you can build complex test suites at minimal cost.
HttpUnit can be broken down into two core components:
- A Web client that sends requests and receives responses
- A collection of methods that analyze and verify response content
Does using HttpUnit equate to unit testing?
Contrary to what its name might imply, HttpUnit does not actually address unit testing. In fact, HttpUnit is more geared towards functional or "black box" testing. Tests that you write using HttpUnit will query the Web server externally and enable you to analyze the responses received. Functional testing plays an important role in XP methodology, which stresses functional testing so that developers can get feedback about the overall state of their system. With unit testing, sometimes the big picture gets lost. Automated functional testing can save developers from the drudgery of manually inspecting areas of a site as the entire site makes its way to production. In a Web environment, some experts feel that each request-response cycle is atomic, and that these atomic cycles can in turn be treated as a single unit of code, and therefore use of HttpUnit can be considered unit testing. Rather than add to this philosophical discussion, let's move on and get to work!
Our sample application consists of an HTML file where one enters a temperature to be converted from Celsius to Fahrenheit or vice versa. The conversion process will be carried out by a servlet and results will be returned to a JSP for presentation. Of course, we could do all of this on the client side using JavaScript, but using the different Web components will demonstrate the value of testing with HttpUnit.
This section assumes that you don't have a test server set up on your machine. To create a server in Application Developer, open the Server perspective. In the Server configuration pane, right-click on the Servers folder and select New => Server and server configuration.
On the next screen, specify a Server name of
TestServer and choose a Server type of
WebSphere Version 5.0 Test Environment.
Click Next. If asked if you would like to create a new server
project with the name Servers, click
Yes.
You are presented with a dialog in which you can specify the HTTP port
which the test server will listen to. Keep the default setting of
9080 and click Next.
You can access the Temperature Converter project EAR file by downloading tempprojectfiles.zip. In the Studio workspace, select File => Import.
Choose an import source of EAR file. On the next screen, browse to
your EAR file on your hard disk, name your project
TemperatureConversionProject, and click
Finish.
Testing the application manually
At this point, you should be able to test the application manually. Start
the test server and point your Web browser to
http://localhost:9080/TempConvertHttp/TemperatureEntry.html.
This should bring up the Temperature Conversion Application:
Experiment with the application to see how it works. The following screen shot shows the results you should see if you convert 98 Celsius to Fahrenheit:
Here are the formulae for converting from Fahrenheit to Celsius and vice-versa:
C = temperature in degrees Celsius F = temperature in degrees Fahrenheit |
To convert a Fahrenheit temperature into Celsius: C = (F-32)*(5/9)
To convert a Celsius temperature into Fahrenheit:
F = ((9/5)*C)+32
Dissecting the TempConverterServlet
The code below is for TempConvertServlet,
which is the engine that does the temperature conversions. As you can see
from the code, it obtains the temperature to be converted and the task
from the request, calculates the result, and then returns this result
along with the input temperature and task. It then passes control to
conversionResult.jsp.
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet converts temperatures from Celsius to Fahrenheit or vice versa
*/
public class TempConverterServlet extends HttpServlet {
/**
* @see javax.servlet.http.HttpServlet#void (javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse)
*/
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String convertMe = req.getParameter("convertMe");
double whatToConvert = Double.parseDouble(convertMe);
System.out.println("Converting" + whatToConvert);
double converted =0.0;
String conversionType = req.getParameter("howToConvert");
if (conversionType.equals("C2F"))
{
converted = (9*(whatToConvert)/5)+32;
}
else if (conversionType.equals("F2C"))
{
converted = (5*(whatToConvert-32))/9;
}
String convertedString = Double.toString(converted);
req.setAttribute("ConversionResult",convertedString);
req.setAttribute("ConversionSource",convertMe);
req.setAttribute("ConversionMethod",conversionType);
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher("conversionResult.jsp");
dispatcher.forward(req,resp);
}
/**
* @see javax.servlet.http.HttpServlet#void (javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse)
*/
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
} |
Reporting results with conversionResult.jsp
Take a look at the code for
conversionResult.jsp. It simply extracts the
information from the request object that we had stored earlier in
TempConverterServlet. You will see some
embedded scriptlets to facilitate a dynamic presentation of the results.
Notice that we present our results in the JSP in the form of an HTML table. Below you will see a matrix layout of the table and a visualization of how the table can be broken down into rows and columns. In the matrix below, a table cell is described in the format of [i][j], where i is the row and j is the column. Looking at the matrix below, 208.4 is located in row 1, column 2 (rows and columns are zero-indexed). We will use this information in our automated testing.
Creating your test Java project
In Application Developer, create a new Java project named
TestHttpProject. In the Projects tab of the
Java settings, check the TempConvertHttp project.
In the Libraries tab, click Add External JARs and point to the
following JAR files:
httpunit.jar, js.jar, junit.jar, servlet.jar,
Tidy.jar. All of these JAR files are located in the HttpUnit project ZIP file,
which you can download from
sourceforge.net.
Once you have added the JARs, click Finish.
Right-click on TestHttpProject, select Import => File System, and then click Next. Browse to the directory that contains the extracted project files located in the project ZIP file and check TempConverterTester.java, then click Finish.
Analyzing the TempConverterTester
TempConverterTester extends the class
junit.framework.TestCase. This derivation is
necessary to set up our test as a JUnit test. Reflection is used by the
JUnit framework to look for methods in our class which begin with test.
This is done when the TestSuite constructor is
invoked in the code:
public static Test suite()
{
return new TestSuite(TempConverterTester.class);
}
The suite static method is called in our main method with the code:
public static void main(String[] args)
{
junit.textui.TestRunner.run(suite());
}
|
Scrutinizing the testConvertsCorrectlyWithServletUnit() Method
public void testConvertsCorrectlyWithServletUnit()
{
try
{
System.out.println("Starting Conversion Results Test with ServletUnit");
ServletRunner sr = new ServletRunner();
sr.registerServlet( "TempConverterServlet", TempConverterServlet.class.getName() );
ServletUnitClient sc = sr.newClient();
WebRequest request = new PostMethodWebRequest(
"http://localhost:9080/TempConvertHttp/TempConverterServlet" );
request.setParameter("convertMe", "100" );
request.setParameter("howToConvert","C2F");
WebConversation wc = new WebConversation();
WebResponse resp = wc.getResponse( request );
String[][] tableContents = resp.getTables()[0].asText();
assertEquals("100",tableContents[0][2]);
assertEquals( "212.0", tableContents[1][2] );
System.out.println("Conversion Results Test with ServletUnit Completed");
System.out.println("----------------------------------------");
}
catch(Exception e)
{
e.printStackTrace();
}
} |
Let's take some time to analyze this method, as it is the heart of our test:
ServletRunner sr = new ServletRunner(); sr.registerServlet( "TempConverterServlet", TempConverterServlet.class.getName() ); |
We first instantiate an instance of
ServletRunner, which is part of the ServletUnit
framework, a companion framework that ships with HttpUnit. The ServletUnit
framework lets one test in a "simulated servlet container". We then
register our servlet in ServletRunner.
In the HttpUnit API, the WebRequest object represents a request to our server:
WebRequest request = new PostMethodWebRequest( "http://localhost:9080/TempConvertHttp/TempConverterServlet" ); |
We use the setParameter method of the WebRequest object to set parameters and their corresponding values:
request.setParameter("convertMe", "100" );
request.setParameter("howToConvert","C2F"); |
This is a much more elegant method than adding name-value pairs to the end of a URL, as described above. For larger testing endeavors, the organization of the setParameter methodology is much better.
Our actual conversation with the server takes place with the code:
WebConversation wc = new WebConversation(); WebResponse resp = wc.getResponse( request ); |
The WebConversation is an implementation of the HttpUnit WebClient class. In essence, WebConversation acts like a Web Browser. Where the WebRequest object represents a request to the server, the WebResponse object encapsulates the reply. You can do much more with the WebConversation than is presented in this simplistic scenario. A WebConversation object can maintain advanced client state attributes like cookies, relative URLs, and framesets.
The HttpUnit API lets you inspect the response from a request. As you
recall, the servlet passes control back to
conversionResult.jsp. If things are working
with our temperature conversion utility, a conversion from 100 Celsius
should yield 212 Farenheit.
If you recall, in the resulting JSP, the source temperature value is found in table cell [0][2], and the result is in table cell [1][2].
String[][] tableContents = resp.getTables()[0].asText(); |
The code resp.getTables()[0] lets us access our
first (and only) table in our resulting page. Using the HttpUnit API, we
are able to extract the table contents from our resulting page in a
two-dimensional String array.
We verify that our application is converting temperatures directly with the code:
assertEquals("100",tableContents[0][2]);
assertEquals( "212.0", tableContents[1][2] ); |
Here we tap into the offerings of JUnit. We use its
assertEquals method to make sure that our cell
contents are equal to what we expect them to be. When you run the
TempConverterTester class, you should see this
in your console:
You might want to play around with the code of
TempConverterServlet and deliberately alter the
conversion method to see how the test will react. Below is a screen shot
of the results of a test gone bad:
This article described HttpUnit, then introduced you to a sample application in which HttpUnit was applied. You saw how HttpUnit, JUnit, and ServletUnit can be used automate Web application testing. According to the XP philosophy, both black-box testing and unit testing are essential for creating stable Web applications. The open-source APIs of HttpUnit, JUnit, and ServletUnit can be used to create full-fledged, automated testing solutions that you can customize for the Web site testing needs of your enterprise.
| Name | Size | Download method |
|---|---|---|
| tempprojectfiles.zip | .1 MB | FTP |
Information about download methods
- For further information about HttpUnit, see the
HttpUnit home page.

Kulvir Singh Bhogal is an IBM Software Services for WebSphere Consultant, devising and implementing Java-centric solutions at customer sites across the United States. You can reach Kulvir at kbhogal@us.ibm.com .




