Table of Contents
This chapter will present how to write tests for your resources using Jersey Test Framework and how to run them in various containers. Additionally it will explain how to create new module for not yet supported container.
Jersey currently provides following modules:
There are some significant breaking changes in Jersey 1.2. In prior Jersey versions users were able to select container factory just by specifying it in some property. That was convenient from user perspective but not good from build perspective. Former test framework artifact was dependent on all containers which is useless in most cases (usually you test only with one container).
Solution to this is modularization - make module for each
test container. It has one drawback: users will have to have other
dependency in their applications, for example if you want to test
on embedded grizzly container, you will declare (only) dependency
on jersey test framework grizzly module. You can declare multiple
test containers this way and select one by defining property
jersey.test.containerFactory
.
Another change (non-breaking) is renaming Jersey parameters which control container factory, used port and host name for external container. Old properties are still working but users are encouraged to use new ones.
Table 7.1. Property name changes
Prior Jersey 1.2 | Jersey 1.2+ |
---|---|
test.containerFactory | jersey.test.containerFactory |
JERSEY_HTTP_PORT | jersey.test.port |
JERSEY_HOST_NAME (used with external container) | jersey.test.host |
When you want test your resources in maven-based project, you need to add dependency on one of the Jersey Test Framework modules. You can take a look at helloworld sample pom file. There is declared dependency on:
<dependency> <groupId>com.sun.jersey.jersey-test-framework</groupId> <artifactId>jersey-test-framework-grizzly2</artifactId> <version>${project.version}</version> <scope>test</scope> </dependency>
which means that Grizzly Web container (version 2.x) will be used for testing.
You can specify more than one module in dependencies and choose which
module will be used by jersey.test.containerFactory
property.
Every module should contain at least one container factory.
com.sun.jersey.test.framework.spi.container.grizzly.web.GrizzlyWebTestContainerFactory
com.sun.jersey.test.framework.spi.container.grizzly.GrizzlyTestContainerFactory
com.sun.jersey.test.framework.spi.container.grizzly2.web.GrizzlyWebTestContainerFactory
com.sun.jersey.test.framework.spi.container.grizzly2.GrizzlyTestContainerFactory
com.sun.jersey.test.framework.spi.container.http.HTTPContainerFactory
com.sun.jersey.test.framework.spi.container.inmemory.InMemoryTestContainerFactory
com.sun.jersey.test.framework.spi.container.embedded.glassfish.EmbeddedGlassFishTestContainerFactory
com.sun.jersey.test.framework.spi.container.external.ExternalTestContainerFactory
Basically you can just add dependency on single module and its container factory would be used. Problem is when you specify module which has more than one container factory or multiple modules. If this happen, test framework will choose factory using following rules:
if("jersey.test.containerFactory" not specified) look for factories if(factories.count == 1) use found factory else if(com.sun.jersey.test.framework.spi.container.grizzly2.web.GrizzlyWebTestContainerFactory is present) use it // current default jersey test container factory else use first found and log warning else use factory class specified in "jersey.test.containerFactory"
That means if your project depends on multiple test framework modules and you want to control which will
be used, you have to declare which one in property called "jersey.test.containerFactory", for example like this:
mvn clean install -Djersey.test.containerFactory=com.sun.jersey.test.framework.spi.container.inmemory.InMemoryTestContainerFactory
Jersey Test Framework uses JUnit version 4.X, so if you can write standard unit tests, you can easily create Jersey Test. You need to declare test as a descendant of JerseyTest class.
public class MainTest extends JerseyTest { public MainTest()throws Exception { super("com.sun.jersey.samples.helloworld.resources"); } @Test public void testHelloWorld() { WebResource webResource = resource(); String responseMsg = webResource.path("helloworld").get(String.class); assertEquals("Hello World", responseMsg); } }
Note super
call in constructor - it passes list of package names to scan (it really is a list,
JerseyTest constructor has variable argument count). Another useful method is
resource()
which returns WebResource instance with URI set to base URI of your application.
You can get preconfigured Jersey Client instance similarly by calling client()
method.
Creating your own module is pretty straightforward, you just have to implement com.sun.jersey.test.framework.spi.container.TestContainerFactory
and com.sun.jersey.test.framework.spi.container.TestContainer
. TestContainer factory is there basically for returning TestContainer instance and
TestContainer has self-explanatory methods: start()
, stop()
, getClient()
and getBaseURI()
.
I recommend taking look at source code and read javadoc of these two classes, all you need is there.
You should be avare of another thing when implementing own jersey test framework module. If you want it to be
usable by running just mvn clean install
(when only your module is specified), you need to add
META-INF/services/com.sun.jersey.test.framework.spi.container.TestContainerFactory file into your jar and put there
your factory class (fully classified) name.
Since Jersey is Maven based project, executing tests without Maven can be painful. You have to have everything needed present on classpath and by everything is meant following list:
This is needed to run helloworld
sample tests, if you want run something more complex or
with different test container (grizzly is used here), you may need to add other application specific dependencies
(and remove some as well).
As was already written above, Jersey test is descendant of standard unit test so it can be run same way.
You can execute it by executing org.junit.runner.JUnitCore
and passing your test class name
as parameter, from ant (junit-task)
or whatever you are used to.