The geekier side of Riff Pie

Unit-testing RESTful Jersey services glued together with Spring

Monday, August 9th, 2010

So I’ve recently been playing around with building RESTful web services using Jersey, the production-quality reference implementation of JAX-RS. It’s a neat library, and, to my mind, simpler than other offerings such as Restlet.

However, this post isn’t yet another Jersey tutorial, there are millions of them already. I’ve found the quickest way to develop REST services is top-down, layer-by-layer, feature by feature, and it’s also one of those areas where test-driven development really shines. Luckily, Jersey comes with some good support for unit-testing, in the shape of the JerseyTest class, which leverages a bunch of container adapters to allow you to quickly and easily deploy resources to a container programmatically, and fire real HTTP requests at it. I use the excellent lightweight Grizzly container for this, it’s what works by default.

There’s a problem, though. I like wiring things together with Spring, and although Jersey provide a servlet for configuring your app with Spring, resources and all, it doesn’t actually let you get at the application context, so getting hold of beans from it is a no-no. Using Spring’s JUnit support doesn’t help, because both it, and the Jersey test, create separate, identical contexts. This means, if you need to use something from the context in your actual tests, you can’t. I want to. I like having my resources delegating down to a service layer, and I like mocking this layer out for some tests.

So after a few quickly-dead ideas involving awkward factory methods that let me reach into specific classes in the context, and a singleton servlet for testing – yuck – I had a dig about in the Jersey source code and came up with a little tweak, and subclassed JerseyTest to give trivially easy access to it. If you’ve used JerseyTest, you’ll be right at home, it works exactly the same way. Use the WebappDescriptor.Builder to configure your app, make sure your Spring context allows annotation configuration, and use Spring’s @Autowired in your test class to get any dependencies you need from your context.

Onwards with the obligatory example.

In the following test, I have a RESTful resource which delegates to an some service or other for some work. I want, for unit-testing purposes, to mock out this service. That means, both the RESTful service and the unit test need a reference to the same mocked service. Here’s the test class, with an instance variable declared to hold the service in question, annotated as Spring @Autowired.

public class JerseySpringTestSupportTest extends AbstractSpringAwareJerseyTest {
 
	public JerseySpringTestSupportTest() {
		super(new WebAppDescriptor.Builder("com.riffpie.common.testing.jersey.resources")
        .contextPath("testing")
        .contextParam("contextConfigLocation", "classpath:test-spring-jersey-integration-context.xml")
        .contextListenerClass(ContextLoaderListener.class)
        .build());
	}
 
        @Autowired
	private ArbitraryService service;
 
	@Test
	public void testServiceWorks() throws Exception {
 
		String input = "this is the input";
		String output = "THIS IS THE OUTPUT";
 
		Mockito.when(service.getEcho(input)).thenReturn(output);
 
		String response =
                          resource()
                          .path("echo")
                          .queryParam("input", input)
                          .accept(MediaType.TEXT_PLAIN)
                          .get(String.class);
 
		assertEquals(output, response);
 
		Mockito.verify(service).getEcho(input);
 
	}
}

And here’s the associated Spring config. I use Mockito to mock out a service – which I won’t patronise you by posting here – and inject it into the resource, which I also won’t post here.

 
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
 
    <context:annotation-config />
 
   	<bean id="testResource" class="com.riffpie.common.testing.jersey.resources.EchoResource">
   	  <property name="service" ref="delegate"/>
   	</bean>
 
	<bean id="delegate" factory-method="mock" class="org.mockito.Mockito">
	  <constructor-arg value="com.riffpie.common.testing.jersey.ArbitraryService"/>
	</bean>
 
</beans>

Your test instances are passed to the application context for auto-wiring, all the necessary dependencies are injected, and you’re away. Simples.

Well, if it’s source code you’re after, release 1.0 of the test class is available here. The source includes the actual classes used, as well as a more complete unit test than the one presented here. If you’re a Maven user, add my Maven repo http://maven.riffpie.com/releases/ to your POM, your settings.xml, repo manager or what have you, and use this snippet in your POM to use the library yourself. I’ve even included out-of-the-box support for cookies, which usually takes a bit of buggering about with Jersey clients.

  <dependency>
    <groupId>com.riffpie.common.testing</groupId>
    <artifactId>jersey-test-support</artifactId>
    <version>1.0</version>
  </dependency>

Unit tests have all sorts of uses, y’know

Monday, April 26th, 2010

Unit tests are marvelous things, I don’t believe it’s even necessary to make a case for them any more. But what is it that they do? Aside from “oh, test units” of course. Well, what they really do is they allow you as a developer, to test certain assumptions you’ve made. You might, for example, assume that certain values passed into a method will cause a certain value to come back, and use unit tests to check that. Or that invalid input will be gracefully handled, rather than bringing the entire app crashing to the ground. That sort of thing. But they can be used to test other assumptions, too. They can be used to test assumptions about, say, the environment in which they’re being run.

Something else unit tests are useful for is a means of communication. Want to know how to use a particular API? A good place to start might well be the documentation, but another good place is often the unit tests for that API. After all, what is a suite of tests, if not a (hopefully) comprehensive example of how to use particular pieces of code? Documentation might well explain that to call method doFoo, you have to construct both a Bar object and a Baz object, and pass them into doFoo, but seeing a unit test actually doing it speaks volumes. But unit tests can also be used to communicate other things. Like what your build environment should be.

See where I’m going with this?

How often have you tried to build some code on your machine, and failed, only to discover later that your box wasn’t set up right for the build? It happens to devs here all the time, and it’s a nuisance. Example: you check out a large project, run the build, and get a whole raft of test failures. The continuous integration build is working fine, no other dev is having similar problems, but you can’t build it. A bit of digging into test failures, and you find that, say, some database tests are dependent on a particular host name being pointed at your local machine. Or a bit of asking around reveals that you need a certain properties file in a certain location, with certain values present, in order to get it working. Now, it’s really questionable that such things need be true at all for a developer build to work, and if you’re in this situation, perhaps your local build is doing too much and it’s time to look at staged builds. However, that’s a different nut to crack.

If you are in a place where these not-really-unit-tests are being run on developer boxes, you can leverage unit tests to ascertain very quickly whether the build environment is correct, and report on what’s missing. Build dependent on a properties file? Write a test that checks for it, early:

@Test
public void testStoreIDPropertiesPresent() {
  String filename = "/etc/company/properties/store.properties";
  File propertiesFile = new File(filename);
  Assert.assertTrue("You don't seem to have the file '" + filename +" ' on your machine", propertiesFile.exists());
}

Likewise, if the database tests rely upon a host name, write a test that makes sure it can connect, and catches the appropriate exception. Or anything else you care to think of. Give it a meaningful name, because in a Maven build, you’ll spot that failing a mile off, without having to go trawling through Surefire reports to find the cause of the failure.

Of course, if there are such quirks of your build, you really ought to be documenting them – a README in the root of the project works wonders, but there’s no harm in checking the environment, rather than just assuming it’s been set up correctly. As a build increases in complexity, the likelihood of there being quirks like dependencies on the environment increases. The worst thing you can do is rely on word-of-mouth to communicate them. Documenting them is a good idea, of course. I’ve heard several different ideas floating around regarding exactly how. “Put them on a wiki page”, “create a ‘starter pack’ full of documents about these things”, “provide a README” etc. All well and good, but the thing about such documentation is, it’s used as a sort-of getout clause by the guy writing it. “I’ve put it all on the wiki, it’s not my fault if nobody bothers to read it”. Err, no. That’s a poor attitude to take. Documentation is a passive medium, we shouldn’t just assume everybody’s read it. Human nature being what it is, it’s folly to do so, and worse to hide behind such assumptions in order to absolve ourselves of responsibility. If “documenting things” was such an infallible medium, it’s unlikely we’d need unit testing in the first place.

I’ve talked specifically about leveraging unit tests to check that a build environment is in order, because it’s something I get bitten by frequently, and see others around me being similarly bitten. I’m sure it’s not the only side-usage of unit tests there is. I’d love to hear about how others are using them for things other than merely testing code.