5.5 Following Hyperlinks

5.5.1 Problem

You want to obtain hyperlinks, simulate clicking on them, and test that the correct response is returned.

5.5.2 Solution

Use the WebResponse.getLinkWith( ) method to obtain a WebLink object, then call WebLink.getRequest( ) to get a new WebRequest that you can execute. Executing this second request simulates the user clicking on the link.

5.5.3 Discussion

The HTTP protocol is a series of requests and responses. Following a hyperlink is merely a case of issuing an HTTP GET request and checking the response. As you are adding new links to your web application, you should attempt to write a test first. The first time you run the test, it fails because the link does not exist. Here is a test that obtains a hyperlink and then attempts to follow it:

public void testFollowLinkToSubscriptionPage(  ) throws Exception {
    // get the home page
    WebConversation webConversation = new WebConversation(  );
    WebResponse response = webConversation.getResponse(
            "http://localhost:8080/news");

    WebLink subscriptionLink = response.getLinkWith("subscription");

    // get a request to simulate clicking on the link
    WebRequest clickRequest = subscriptionLink.getRequest(  );

    // throws HttpNotFoundException if the link is broken
    WebResponse subscriptionPage =
            webConversation.getResponse(clickRequest);
}

The WebResponse.getLinkWith( ) method searches for the first hyperlink in the web page that contains some piece of text. In our example, we are searching for a link like this:

<a href="someUrl">subscription</a>

This illustrates how HttpUnit uses the JTidy library to parse the HTML. You call the getLinkWith( ) convenience method, and HttpUnit uses JTidy to search the DOM tree for the first matching hyperlink. If one is not found, the WebLink object will be null.

Once you have the WebLink object, you get a new WebRequest and ask it for a new WebResponse:

// get a request to simulate clicking on the link
WebRequest clickRequest = subscriptionLink.getRequest(  );

// throws HttpNotFoundException if the link is broken
WebResponse subscriptionPage = 
        webConversation.getResponse(clickRequest);

If you are following a test-first approach, the link will not be valid. It is a good idea to run the faulty test first, just to prove to yourself that your test catches the problem should the link actually fail sometime in the future. Now you can write your servlet to generate the subscription page:

public class NewsletterServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req,
                         HttpServletResponse res)
            throws ServletException, IOException {
        res.setContentType("text/html");
        PrintWriter pw = res.getWriter(  );
        pw.println("<html>");
        pw.println("<body>");
        pw.println("<h1>NewsletterServlet</h1>");
        pw.println("</body>");
        pw.println("</html>");
    }
}

Notice how, in the test-first approach, you don't write the complete servlet. Instead, you create a stubbed-out page that generates a minimal response. You can now run your test suite again, and should see that the link is valid and the test passes. This is also a good time to go back to your web browser and bring up the web page and try out the hyperlink interactively.

5.5.4 See Also

The WebLink class also provides a click( ) method that returns a WebResponse object.