Unit Testing Jersey RESTful Web Services That Also Use The Spring Framework
Introduction
In a previous blog article I described how you can integrate Jersey RESTful web services and the Spring framework. I ended that article with a note that I needed to do further research into how to write unit tests for the web services that depend on the Spring framework for dependency injection.
Fortunately, I ran across an article on Naresh's blog, Jersey Test Framework re-visited, where he explains the new version (1.1.2-ea) of the Jersey test framework. In his article he provides a link to the code for the spring-annotations sample test (provided as part of the Jersey project), which is an example of unit testing a web service that uses Spring. So using Naresh's article and the Spring annotations example code I was able to design a demo application that uses Jersey and Spring and that includes some simple unit tests.
Example Application
Download the example application (a Maven project) and unzip it on your computer. Open a terminal (command) window and navigate to where you unzipped the project. You want to be in the same directory as the pom.xml for this project (see the references below if you're not familiar with using Maven).
In the terminal window enter the command mvn clean and then when that finishes enter mvn test -DenableLogging. Maven will then execute the tests. There are six tests in two different classes: TestCourseDao and TestCourseResource. The -DenableLogging setting will cause the Jersey test framework to display the client's HTTP request and the server's HTTP response, which can be very useful (and reduce the need for writing your own log statements in the test code).
You can also run the application by typing mvn jetty:run in the terminal window. When you see [INFO] Started Jetty Server, open a web browser and navigate to this URL: http://localhost:8080/BlackboardDemo/index.html. You should see a list of courses associated with user IDs.
If your Java IDE supports Maven (I'm using Eclipse 3.5 with the Maven 2 plugin) you should be able to import this Maven project. If not you can view the source code using a text editor or copy the source files into your IDE.
Be sure to review the pom.xml for all the dependencies and their version numbers. There were some problems with certain combinations of previous Spring and JUnit releases.
Testing the Web Services
I recommend you first read Naresh's blog article, Jersey Test Framework re-visited, and look over the Spring annotations example code before studying the TestCourseResource class in my example application. There have been several changes in the Jersey test framework API with the 1.1.2-ea release. For example, in the constructor of the TestCourseResource class I use the WebAppDescriptor.Builder to build the application descriptor. This is quite different then how it was done in the previous releases of the Jersey test-framework.
@Override
protected TestContainerFactory getTestContainerFactory() {
return new GrizzlyWebTestContainerFactory();
}
public TestCourseResource() throws Exception {
super(new WebAppDescriptor.Builder("com.sun.jersey.samples.springannotations.resources.jerseymanaged")
.contextPath("BlackboardDemo")
.contextParam("contextConfigLocation", "classpath:applicationContext_TEST.xml")
.servletClass(SpringServlet.class)
.contextListenerClass(ContextLoaderListener.class)
.build());
}
Most of the above should be self-explanatory. Note that I've overridden the getTestContainerFactory method so that it returns a GrizzlyWebTestContainerFactory since I'm using the Grizzly container to test the Web services.
In a unit test I do the following.
@Test
public void testGetCourses() throws Exception {
WebResource webResource = resource();
String courses = webResource.path("courseservices")
.accept(MediaType.APPLICATION_XML).get(String.class );
assertTrue("Courses does not contain English 101", courses.contains("English 101") );
log.debug("Courses are: " + courses );
}
In the above test method, I get a WebResource object by calling the resource method (inherited from the JerseyTest class. I then specify the path to the web service (courseservices). This matches the @Path annotation on class CourseResource. The get(String.class) part of the method chain specifies that the return type of XML should be converted to a String (see class WebResource's get method). I then use the JUnit assertTrue method to assert that English 101 is part of the String returned by the Web service.
If you study the Spring annotations test code, you'll see where in one of the tests the get method of class WebResource is used to get a specific type (convert the XML to that type) and then store an Object of that type into a local variable (see method doTestSpringAutowired). Unfortunately, I was not able to get a similar test example to work in my application since my Web services return a collection of Course objects (multiple course nodes in the XML). I couldn't figure out how to use the get method with a Collection (if you know how please post a comment).
UPDATE - After studying more of the Jersey test examples I was able to figure out how to design a test that would use the get method of class WebResource to get a collection of Course objects. The first step was to create a class named Courses that has an instance field named Course of type List. I annotated the Courses class with @XmlRootElement so that the XML being returned by the web service could be converted into an instance of this class. Note that if you examine the test data, you'll see that the XML being returned has a courses root node and then 1 or more course nodes. See method testGetCourseList in class TestCourseResource.
Summary
I'm now able to create RESTful web services using Jersey and Spring and to test those services with JUnit. I'm just starting out using Jersey and especially its test framework. So please comment below if you have some up-to-date knowledge to share on these topics.
References
- Jersey Test Framework re-visited, Naresh's Blog
- Spring annotations test example
- Jersey Test Framework API, release 1.1.2-ea
- Using Jersey (RESTful Web Services) and Spring (Dependency Injection) Together
- Create a simple RESTful Webservice with Jersey and Spring, Rafael Sobek
- Jersey-Spring API
- Jersey and Spring, Paul Sandoz
- Jersey, Spring, and JPA, David Sells
- An Introduction to Creating RESTful Web Services Using Jersey and Java, Bruce Phillips Blog
- An Example of Using Jersey RESTFul Web Services, Java, Ajax, and JavaScript, Bruce Phillips Blog
- JAX-RS, the Java API for RESTful web services
- jsr311-api 1.0 API
- Jersey, Sun's Reference Implementation for JAX-RS
- RESTful Web Services Developer's Guide, Sun MicroSystems
- Jersey Test Framework, Naresh's Blog
- Introduction to the Spring Framework
- Spring Framework
- Spring Framework Bean Scope
- Maven: The Definitive Guide, http://www.sonatype.com/books/maven-book/reference/public-book.html
- Developing with Eclipse and Maven, http://www.sonatype.com/books/m2eclipse-book/reference/index.html
Can be referred to as a good tutorial for the Jersey Test Framework :)
I have a question. How to mock up resource dependencies? Usually the resource uses other objects and sometimes I need to mock them. How to do this?
But, I cannot make it work with Spring's @Autowired bean in my web service. I keep getting NullPointerException no matter what I do.