7.8 Testing Cookies

7.8.1 Problem

You want to test a servlet that uses cookies.

7.8.2 Solution

Write a ServletTestCase that tests if your servlet correctly handles creating and managing cookies.

7.8.3 Discussion

Cookies are small pieces of information passed back and forth between the web server and the browser as a user navigates a web application. Web applications commonly use cookies for session tracking because a cookie's value uniquely identifies the client. There is a danger for a web application to rely solely on cookies for session tracking because the user may, at any time, disable cookies. For this reason, you must design your web application so that your web application still works if cookies are disabled.

Cactus Proves that Code Works

Cactus provides some comfort when a test passes, because it passed while running in a servlet container. This fact helps prove the code actually works when deployed. This type of test is very useful when testing critical aspects of a web applicationfor example, session tracking. Session tracking usually mixes three technologies (or concepts): URL rewriting, cookies, and the servlet-session API. Typically, web applications use all three in order to provide a robust web application. Testing this part of a web application is challenging. By writing tests that execute in a servlet container, you are helping to guarantee that your code actually works as designed when deployed.

Example 7-5 shows how to write a test for a servlet that uses cookies to keep track of how many times a user has visited the site.

Example 7-5. A simple cookie counter
package com.oreilly.javaxp.cactus.servlet;

import org.apache.cactus.ServletTestCase;
import org.apache.cactus.WebRequest;
import org.apache.cactus.WebResponse;

import javax.servlet.http.Cookie;

public class TestCookieServlet extends ServletTestCase {

    private CookieServlet servlet;

    public TestCookieServlet(String name) {
        super(name);
    }

    protected void setUp(  ) throws Exception {
        this.servlet = new CookieServlet(  );
    }

    public void testGetInitialCookie(  ) throws Exception {

        Cookie cookie = this.servlet.getCookie(this.request);
        assertNotNull("Cookie.", cookie);
        assertEquals("Cookie Name.",
                     CookieServlet.TEST_COOKIE_NAME,
                     cookie.getName(  ));
        assertEquals("Cookie Value.",
                     "0",
                     cookie.getValue(  ));
    }

    public void beginGetUpdatedCookie(WebRequest req) {
        req.addCookie(CookieServlet.TEST_COOKIE_NAME, "3");
    }

    public void testGetUpdatedCookie(  ) throws Exception {
        this.servlet.doGet(this.request, this.response);
    }

    public void endGetUpdatedCookie(WebResponse res) throws Exception {
        org.apache.cactus.Cookie cookie =
                res.getCookie(CookieServlet.TEST_COOKIE_NAME);
        assertNotNull("Returned Cookie.", cookie);
        assertEquals("Cookie Value.", "4", cookie.getValue(  ));
    }
}
7.8.3.1 testGetInitialCookie( )

This test simulates a user hitting the servlet for the first time. The CookieServlet tests that the getCookie( ) method returns a Cookie that is not null, has a name defined by the constant CookieServlet.TEST_COOKIE_NAME, and whose value is zero.

7.8.3.2 testGetUpdatedCookie( )

This test is a little more complicated because it requires the request to be set up properly before invoking the doGet( ) method on the CookieServlet. Remember that before Cactus invokes a testXXX( ) method, it looks for a beginXXX( ) method to execute on the client.

The code to add a cookie to the request looks like this:

public void beginGetUpdatedCookie(WebRequest req) {
    req.addCookie(CookieServlet.TEST_COOKIE_NAME, "3");
}

Now Cactus invokes the testGetUpdatedCookie( ) method on the server. This test calls the doGet( ) method on the CookieServlet to simulate an HTTP GET.

public void testGetUpdatedCookie(  ) throws Exception {
    this.servlet.doGet(this.request, this.response);
}

If the testGetUpdatedCookie( ) method completes successfully, Cactus looks for a method called endGetUpdatedCookie(WebResponse). This method is invoked on the client and allows you to assert that the servlet correctly updated the cookie.

public void endGetUpdatedCookie(WebResponse res) throws Exception {
    org.apache.cactus.Cookie cookie =
            res.getCookie(CookieServlet.TEST_COOKIE_NAME);
    assertNotNull("Returned Cookie.", cookie);
    assertEquals("Cookie Value.", "4", cookie.getValue(  ));
}

The returned response object should contain a non-null cookie whose name is defined by CookieServlet.TEST_COOKIE_NAME. The value of the cookie should be four, exactly one more than the value before invoking the doGet( ) method on the servlet.

Example 7-6 shows the cookie servlet.

Example 7-6. Cookie servlet
package com.oreilly.javaxp.cactus.servlet;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Cookie;
import java.io.IOException;

public class CookieServlet extends HttpServlet {

    public static final String TEST_COOKIE_NAME = "testCookie";

    protected void doGet(HttpServletRequest req, HttpServletResponse res)
            throws IOException {

        Cookie cookie = getCookie(req);
        int count = Integer.parseInt(cookie.getValue(  ));
        count++;
        cookie.setValue(String.valueOf(count));
        res.addCookie(cookie);
    }

    protected Cookie getCookie(HttpServletRequest req) {
        Cookie[] cookies = req.getCookies(  );
        if (cookies != null) {
            for (int i=0; i<cookies.length; i++) {
                if (TEST_COOKIE_NAME.equals(cookies[i].getName(  ))) {
                    return cookies[i];
                }
            }
        }

        return new Cookie(TEST_COOKIE_NAME, "0");
    }
}

The CookieServlet looks for a cookie named testCookie defined by the constant CookieServlet.TEST_COOKIE_NAME. If the cookie does not existit's the first time the user has hit the servletthen a new cookie is created and its value set to zero. The cookie's value is incremented by one and added to the HttpServletResponse to be sent back the client browser.

7.8.4 See Also

Recipe 7.9 shows how to test code that uses an HttpSession object.