Normally, I like to make my unit tests so that they do not depend on external things running. As a general rule, I try to write tests that prove that the logic in my code works. While I care that communication between my application and, say, a database or application server works, it’s not my code that’s doing the communication, so I don’t tend to write unit tests that cover that. If I’m using something like Apache Jakarta Commons’ HttpClient to do some kind of communication via HTTP, I tend to write tests that confirm that the request (PostMethod or the like) is built properly by my code and that my code handles a return result correctly. With some layering it’s possible to structure you code so that these sorts of tests are easy to execute without actually doing the communication.
While I care that the HttpClient does what it’s supposed to, my unit tests tend to be more concerned with whether or not my code does it what it’s supposed to. Sometimes I will write some unit tests for frameworks that I use, but I tend to try and keep these tests isolated. But that’s a story for later.
The other day, I was inspired to write some unit tests that actually do the live communication between my Eclipse plug-in and an application server via HTTP. Setting this up is surprisingly easy using the Jetty and OSGi HTTP service bundles that’re already included with the workbench.
I added the following two methods to my JUnit 4 test class:
@BeforeClass public static void startServer() throws Exception { Dictionary settings = new Hashtable(); settings.put("other.info", SERVER_NAME); settings.put("http.port", 0); JettyConfigurator.startServer(SERVER_NAME, settings); ServiceReference[] reference = Activator.getDefault().getBundle().getBundleContext().getServiceReferences("org.osgi.service.http.HttpService", "(other.info=usagedata.upload.tests)"); Object assignedPort = reference[0].getProperty("http.port"); port = Integer.parseInt((String)assignedPort); tracker = new ServiceTracker(Activator.getDefault().getBundle().getBundleContext(), reference[0], null); tracker.open(); HttpService server = (HttpService)tracker.getService(); server.registerServlet(GOOD_SERVLET_NAME, new GoodServlet(), null, null); server.registerServlet(BAD_SERVLET_NAME, new BadServlet(), null, null); } @AfterClass public static void stopServer() throws Exception { tracker.close(); JettyConfigurator.stopServer(SERVER_NAME); }
This code creates an HTTP server, asking the server to find an available port (which my client code needs to complete the communication) and then registers some servlets.
Some bundles have to be added to my test fragment (I tend to build unit tests for plug-ins in fragments):
- javax.servlet
- org.eclipse.equinox.http.jetty
- org.eclipse.osgi.services
In this example, I’m adding two servlets to the server, one that does good things and one that does bad things. The servlets are mockups of the real things that exhibit very specific behaviour for testing purposes. The code that I’m testing invokes these servlets via the aforementioned HttpClient framework.
I’m still not convinced that this is exactly what I want to do (I certainly have some Law of Demeter issues to work out with it), but it works well. The best part is that my unit tests can be easily automated since they don’t have to depend on some external thing being properly configured.