12.1 Functional Tests


12.1 Functional Tests

The most intuitive way to test Web applications is to open your Web browser, type in the URL you want to visit, and then click off and verify that the application behaves as expected. This has nothing to do with automation, but still. . . . The next step is to use a specialized capture and replay tool that remembers your mouse movements, clicks, and keyboard hits during the first run to then automatically replay them. There is a wide choice of such tools on the market.

Similar options are supported (but directly in Java) by HttpUnit. In contrast to what the name suggests, HttpUnit has little to do with unit testing. HttpUnit is an open source Java API for accessing Web sites without a browser and is ideally suited for automated unit testing of Web sites when combined with a Java unit testing framework such as JUnit. HttpUnit, including extensive documentation, is free and can be downloaded from [URL:HttpUnit]. We can use this functionality for "remote controlling" arbitrary Web applications, but also to test these applications.

The following simple example shows how HttpUnit can be used for testing. Typically, functional tests are retrospective (as opposed to test-first); so we begin with the following simple servlet that is to be tested later:

 import java.io.*; import javax.servlet.http.*; public class MyServlet extends HttpServlet {    public void doGet(HttpServletRequest request,                      HttpServletResponse response) {       doPost(request, response);    }    public void doPost(HttpServletRequest request,                       HttpServletResponse response) {       try {         String name = (String) request.getParameter("name");         PrintWriter writer = response.getWriter();         writer.println("<html><head><title>My Servlet"+                        "</title></head>" +                        "<body>Hello, " + name +                        "!</body></html>");         writer.close();      } catch (Throwable ex) {         ex.printStackTrace();      }    } } 

All this servlet does is insert the passed parameter name into a reply page, Hello, <name>!. We test for simple access to the servlet, using an HTTP GET request to a URL (e.g., http://servername/servlet/MyServlet?name=Johannes):

 import com.meterware.httpunit.*; public class MyServletTest extends TestCase {    private final String SERVLET_URI =       "http://myserver/servlet/MyServlet";    public void testGetRequest() throws Exception {       WebConversation con = new WebConversation();       WebRequest request = new GetMethodWebRequest(SERVLET_URI);       request.setParameter("name", "Johannes");       WebResponse response = con.getResponse(request);       assertEquals("text/html", response.getContentType());    } } 

The starting point is an instance of WebConversation, comparable to a browser session. This object returns an instance of class WebResponse when getResponse(WebRequest) is invoked. In this example, we create an HTTP GET request (GetMethodWebRequest) with a parameter (setParameter(...)). The response object can eventually be consulted for test verification. The first step tested only the content type of the returned page. Let's add more verification items:

 public void testGetRequest() throws Exception {    WebConversation con = new WebConversation();    WebRequest request = new GetMethodWebRequest(SERVLET_URI);    request.setParameter("name", "Johannes");    WebResponse response = con.getResponse(request);    assertEquals("text/html", response.getContentType());    assertEquals("My Servlet", response.getTitle());    assertTrue(response.getText().indexOf("Hello, Johannes!") != -1); } 

We can see that the class WebResponse allows us to access both single html elements—getTitle()—and the full HTML text—getText()—of the response page.

While verifying the HTML code soon becomes unmanageable, the targeted access to tables, forms, and links allows us to verify exactly those elements of an HTML page that are important for correct functioning of the application. We can use HttpUnit to fill in information in Web forms, follow links, and use frames, cookies, and SSL. But it does not support browser script languages like JavaScript. [2]

To understand this better, we will extend the servlet by a form that can be used to change the parameter name and resend the request:

 public class MyServlet extends HttpServlet {    ...    private final String SERVLET_URI = "MyServlet";    public void doPost(HttpServletRequest request,                       HttpServletResponse response) {       try {          String name = (String) request.getParameter("name");          PrintWriter writer = response.getWriter();          writer.println("<html><head><title>My Servlet" +                         "</title></head>" +                         "<body>Hello, " + name + "!");          writer.println("<form name=\"form1\" action=\"" +                         SERVLET_URI + "\">");          writer.println("<input type=text name=\"name\"" +                         value=\"" + name + "\">");          writer.println("<input type=submit name=\"button\" +                         value=\"Change Name\">");          writer.println("</form></body></html>");          writer.close();       } catch (Throwable theException) {          theException.printStackTrace();       }    } } 

The following test specifically accesses the form elements and its children:

 public void testGetRequest() throws Exception {    WebConversation con = new WebConversation();    WebRequest request = new GetMethodWebRequest(SERVLET_URI);    request.setParameter("name", "Johannes");    WebResponse response = con.getResponse(request);    ...    WebForm form = response.getFormWithName("form1");    assertEquals("Johannes", form.getParameterValue("name"));    assertEquals("Change Name",                 form.getSubmitButton("button").getValue()); } 

Figure 12.1 shows what the page now looks like in the browser.

click to expand
Figure 12.1: MyServlet in the browser.

Another test checks whether or not entering a new name and clicking the Change Name button works as desired:

 public void testChangeName() throws Exception {    WebConversation con = new WebConversation();    WebRequest request = new GetMethodWebRequest(SERVLET_URI);    request.setParameter("name", "Johannes");    WebResponse response = con.getResponse(request);    WebForm form = response.getFormWithName("form1");    request = form.getRequest("button");    request.setParameter("name", "Frank");    response = con.getResponse(request);    assertTrue(response.getText().indexOf("Hello, Frank!") != -1); } 

In theory, HttpUnit allows us to also verify the page layout, because we can use the method response.getDOM() to get a DOM-compliant tree representation of a page. [3] In practice, however, such detailed tests often prove to be too fragile to deserve automation.

To do the testing in the form shown here, we have to install the complete Web application on the server. This and the fact that we are testing only on the highest functional level shows clearly that these test cases are not unit tests, but functional tests on system level. As we proceed we will see how HttpUnit can also be used for "real" unit tests.

There exist, meanwhile, a couple of other HttpUnit-like frameworks, for example, the Web Application Testing Framework [URL: WATF]. The drawback of using HttpUnit or a like tool as a functional testing tool is that it requires programming knowledge. As a potential alternative, we could use either a capture and replay tool or develop a project-specific framework allowing us to specify functional tests in textual form, for example, XML as in Canoo-Webtest [URL:Webtest]. This means that we could kill two birds with one stone:

  • The customer or the tester can create test cases independently.

  • We are totally free to define the degree of detail of the test case specification. This means that we can separate everything that will change and has to be tested from what will not change so that we won't have to repeat these things in each new test case.

[2]But there is a special test framework for it, JsUnit [URL:JsUnit].

[3]DOM stands for Document Object Model (see Glossary).




Unit Testing in Java. How Tests Drive the Code
Unit Testing in Java: How Tests Drive the Code (The Morgan Kaufmann Series in Software Engineering and Programming)
ISBN: 1558608680
EAN: 2147483647
Year: 2003
Pages: 144
Authors: Johannes Link

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net