Functional HTTP testing revisited using JUnit 4.7 Interceptors

September 3, 2009

(I originally planned this to be a single article, but because of the scope decided to split it into two parts. Read the first part for the the basics of using Sun’s HttpServer to conduct functional HTTP testing. Here we revisit our functional test and rewrite it using JUnit 4.7’s new Interceptors feature.)

Recap

In my previous post, I demonstrated how to use Sun’s HttpServer API to write a functional test of an HTTP ‘conversation’.

Recall that I thought my initial solution seemed inelegant. It was verbose, with some start up and shutdown code that would have to be repeated for each test, and which I felt cluttered the actual test code.

It was also tedious, in the sense that the raw HttpHandler and HttpExchange API required us to do quite a few things manually, and unintuitively (such as having to compute and write out the length of our response before the response itself).

In this post, we’ll explore how to use the new Interceptors feature ‘quietly’ released with JUnit 4.7 to write reusable, portable pre and post-test behaviour. I’ll also exhibit a convenient HttpHandler implementation that simplifies some of the effort required in responding to HTTP requests.

JUnit Interceptors at a glance

Developers familiar to JUnit will know that prior to JUnit 4.x, to perform pre/post test behaviour such as setting up and tearing down test scaffolding or external resources, we had no choice but to override TestCase#setup() and TestCase#tearDown(). To make this reusable across test classes, we had to extend TestCase and our actual tests had to extend that custom class.

JUnit 4.x introduced annotation-driven testing using the @Test annotation, which allowed us to write tests that were simple POJOs. However, this didn’t help when we wanted reusable pre/post test behavior. We still had to write our custom base class, this time with methods annotated with @Before and @After.

JUnit 4.7 introduces a new feature called “Interceptors” that aims to bring back to JUnit the ability to to ‘meta-testing’ with a much cleaner and simpler API. See Kent Beck’s1 and David Saff’s2 blog posts for more of the inside scoop.

Writing an Interceptor

A good place to start is to look at the source for ExternalResource.

If we need complete control over our interceptor’s behavior, we’d need to implement MethodRule from scratch.

In our case, we can get by simply by extending ExternalResource. We setup our HTTP server in the before() method, and tear it down in our after() method. We also provide a way to specify the port to listen on in our constructor:

public class HttpServerInterceptor extends ExternalResource {

    private final InetSocketAddress address;

    private HttpServer httpServer;

    public HttpServerInterceptor(final int port) {
        this.address = new InetSocketAddress(port);
    }

    protected final void before() throws Throwable {
        super.before();
        httpServer = HttpServer.create(address, 0);
        httpServer.start();
    }

    protected final void after() {
        httpServer.stop(0);
        super.after();
    }

Next, we provide a delegate method to register handlers:

    public void addHandler(String path, HttpHandler handler) {
        httpServer.createContext(path, handler);
    }

Using Interceptors

To use our new JUnit interceptor, all we need to do is annotate a public field with the org.junit.Rule annotation. Note that the field has to be public—this might raise a warning if you use Checkstyle and personally, I wish JUnit would allow private @Rules.

@Rule
public HttpServerInterceptor httpServer = new HttpServerInterceptor(8000);

The JUnit runner does the rest. It’ll transparently call our interceptor’s before() method, run the @Test then call our interceptor’s after() method.

Armed with this, we can rewrite the rest of our HTTP functional test as:

@Test
public void testHttpServer() throws Exception {
    httpServer.addHandler("/1234.xml", new HttpHandler() {

        public void handle(HttpExchange exchange) throws IOException {
            byte[] response = "<?xml version=\"1.0\"?>\n<resource id=\"1234\" name=\"test\" />\n"
                    .getBytes();
            exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, response.length);
            exchange.getResponseBody().write(response);
            exchange.close();
        }
    });

    // exercise our client code
    URL url = new URL("http://localhost:8000/1234.xml&quot;);
    URLConnection conn = url.openConnection();
    BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    assertEquals("<?xml version=\"1.0\"?>", in.readLine());
    assertEquals("<resource id=\"1234\" name=\"test\" />", in.readLine());
}

Simplifying our Handlers

We’ve managed to cut out some of our test scaffolding code. Now let’s simplify our actual handler. For this, I wrote SimpleHttpHandler, which is an HttpHandler which provides delegate methods to the actual HttpExchange. That is, by extending SimpleHttpHandler we can simply go getRequestURI() instead of having to go httpExchange.getRequestURI().

Additionally, SimpleHttpHandler uses an internal ByteArrayOutputStream, exposed via a PrintWriter in the getResponse() method. This lets us simply write our response as if, say, to System.out, and it takes care of computing the total response length later on when we call the sendResponse() method.

Here’s the same handler above rewritten using SimpleHttpHandler:

    httpServer.addHandler("/", new SimpleHttpHandler() {

        protected void onGet() throws IOException {
            getResponse().println("<?xml version=\"1.0\"?>");
            getResponse().println("<resource id=\"1234\" name=\"test\" />");
            sendResponse(HTTP_OK);
        }
    });

The complete source to HttpServerInterceptor and SimpleHttpHandler are provided as part of junit-rules, a ‘pet’ project I’ve made to explore and showcase JUnit Rules.

Hopefully, I’ll be able to add other, useful rules to junit-rules. Feel free to download, study and use it. Better yet, if you want to share any useful rules of your own, by all means, please fork or contribute to it!

(Edit 2009/10/16: Changed links/references to junit-interceptors to junit-rules, all because I misread Kent Beck’s post—they were renaming it to Rules from Interceptors, and not the other way around!)

References

1 Interceptors in JUnit
2 JUnit 4.7: Interceptors: expected exceptions

About these ads

One Response to “Functional HTTP testing revisited using JUnit 4.7 Interceptors”


  1. I had a look into the External Resource interceptor and came up with a similar solution a while back – just for an example usage. This looks like a good usage similar to what I considered..and great to see…will give it a roll some time.

    My example – which is not as well presented or through as yours is here…
    http://www.catosplace.net/blogs/personal/?p=187

    Looking in to all the interceptors and trying to come up with ideas/uses.

    Thanks for the article.

    Pete.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: