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

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:

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.

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.

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!)

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.