That is a quick one. These days I was playing around with Jersey in order to create a rest web service. The thing is that I would like to test what I create. The good thing is that Jersey provides a testing framework. But...
As the project I was working on was a mavenized one, all I had to do was to add the dependency:
<dependency>
<groupId>com.sun.jersey.jersey-test-framework</groupId>
<artifactId>jersey-test-framework-grizzly2</artifactId>
<version>${jersey.version}</version>
<scope>test</scope>
</dependency>
As a quick reminder, you can not only use the grizzly web container with the jersey framework, but as I needed some a way to test the actual http api, I went that way initializing everything I would have initialize at a web container with an in memory database.
So after that you can extend the com.sun.jersey.test.framework.JerseyTest
class and use it with jUnit.
The problem is that the JesreyTest initializes the webcontainer before each test and shut it down after that. That means that the procedure became real slow and I could not run parallel tests as the testing framework would try to initialize the web container twice causing an exception regarding the address that is already in use.
After reading the JerseyTest source code I ended up at the setUp method:
@Before
public void setUp() throws Exception {
tc.start();
}
but as tc was the com.sun.jersey.test.framework.spi.container.TestContainer
class that is getting initialized at the contstractor of the JerseyTest, there was not anything that I could do there!.
As I used the JerseyTest(AppDescriptor ad) you can see here:
public JerseyTest(AppDescriptor ad) throws TestContainerException {
this.tc = getContainer(ad, getTestContainerFactory());
this.client = getClient(tc, ad);
}
I could change two things. Either the getContainer
method or the getTestContainerFactory
. From these two, only the second one was protected and could let me do something like that.
So what I needed was a custom TestContainerFactory that would cache the resulted TestContainer per AppDescriptor. Something like:
class OnePerAppDescriptorTestContainerFactory implements TestContainerFactory {
private static final ConcurrentMap<AppDescriptor, TestContainer> cache = new ConcurrentHashMap<AppDescriptor, TestContainer>();
private final TestContainerFactory tcf;
public OnePerAppDescriptorTestContainerFactory(TestContainerFactory tcf) {
this.tcf = tcf;
}
@Override
public <T extends AppDescriptor> Class<T> supports() {
return tcf.supports();
}
@Override
public TestContainer create(URI baseUri, AppDescriptor ad) {
if (cache.get(ad) == null) {
cache.putIfAbsent(ad, tcf.create(baseUri, ad));
}
return cache.get(ad);
}
}
Now I can wrap any other TestContainerFactory and only use it if I do not have any other TestContainer ready for a given AppDescriptor. The last problem would be a shutdown hook. As I'm using TestNG the @BeforeSuite
with @AfterSuite
annotations worked just fine:
public class BetterJerseyTest extends JerseyTest {
//Fire up jersey with Guice
private static final AppDescriptor APP_DESCRIPTOR = new WebAppDescriptor.Builder("com.some.package.name")
.filterClass(GuiceFilter.class)
.contextPath("jersey-ctx-path")
.servletPath("/")
.clientConfig(new DefaultClientConfig(JacksonJaxbJsonProvider.class))
.build();
public JerseyTestNG() {
super(APP_DESCRIPTOR);
}
@Override
protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
return new OnePerAppDescriptorTestContainerFactory(super.getTestContainerFactory());
}
@BeforeSuite
public void initTestContainer() throws Exception {
setUp();
}
@AfterSuite
public void tearDownTestContainer() throws Exception {
tearDown();
}
}
The jUnit users may have a look here to check how they can implement a shutdown hook or just don't at all :-).