We tried a couple of alternatives before coming up with this solution that uses some of Groovy's support for fluent APIs.
Lets start by looking at the raw boilerplate required to get our embedded Grizzly server working for our PersonResource tests.
void startEmbeddedServer() {
// Create test web application context.
WebappContext webappContext = new WebappContext( "Test Context" )
webappContext.addContextInitParameter( "contextClass", "org.springframework.web.context.support.XmlWebApplicationContext" )
webappContext.addContextInitParameter( "contextConfigLocation", "classpath*:personService-web-applicationContext.xml" )
webappContext.addListener( "org.springframework.web.context.ContextLoaderListener" )
// Create a servlet registration for the web application in order to wire up Spring managed collaborators to Jersey resources.
ServletRegistration servletRegistration = webappContext.addServlet( "jersey-servlet", "com.sun.jersey.spi.spring.container.servlet.SpringServlet" )
// The LinkFilter is required for the HATEOAS annotations, logging filters for server logging.
servletRegistration.setInitParameter( "com.sun.jersey.spi.container.ContainerResponseFilters", "com.sun.jersey.server.linking.LinkFilter;com.sun.jersey.api.container.filter.LoggingFilter" )
servletRegistration.setInitParameter( "com.sun.jersey.spi.container.ContainerRequestFilters", "com.sun.jersey.api.container.filter.LoggingFilter" )
servletRegistration.setInitParameter( "com.sun.jersey.config.property.packages", "com.alkalinezoo.resource" )
servletRegistration.setInitParameter( "com.sun.jersey.api.json.POJOMappingFeature", "true" )
servletRegistration.addMapping( "/*" )
grizzly = GrizzlyServerFactory.createHttpServer( "http://localhost:9998", new DefaultResourceConfig( PersonResource.class ) )
webappContext.deploy( grizzly )
grizzly.start()
}
As you can see there is quite a lot of boilerplate code here. We need a number of test specific details to be supplied, i.e. the package to scan for jersey annotations 'com.alkalinezoo.resource', the location of the Spring applicationConfig 'classpath*:personService-web-applicationContext.xml', the class under test 'PersonResource.class' etc.
There are also a couple of areas that we could improve, for example logging. In the example above Grizzly logging is switched on via the use of the 'LoggingFilter'. It would be nice to be able to switch logging on / off in the test class.
It would be nice if we could specify this test specific configuration when we start the server and not have it embedded in the server config.
So, instead of adding all this config to our tests we have the following implementation:
static final String BASE_URL = 'http://localhost:9998'
static final String BASE_PACKAGE = 'com.alkalinezoo.resource'
static final String SPRING_CONTEXT_LOCATION = 'classpath*:personService-web-applicationContext.xml'
static final String CLASS_UNDER_TEST = 'com.alkalinezoo.resource.PersonResource'
GrizzlyEmbeddedServer server = new GrizzlyEmbeddedServer()
@Before
void setup( ) throws IOException {
server.start { baseURL BASE_URL
resourceBasePackage BASE_PACKAGE
loggingRequired false
springContext SPRING_CONTEXT_LOCATION
testClass CLASS_UNDER_TEST
}
}
@After
void cleanup( ) {
server.stop()
}
The GrizzlyEmbeddedServer class defines a number of methods to set the test specific configuration elements of the class, for example:
private void springContext( String contextConfigLocation ) {
this.contextConfigLocation = contextConfigLocation
}
private void resourceBasePackage( String basePackage ) {
this.basePackage = basePackage
}
private void loggingRequired( Boolean serverLogging ) {
this.serverLogging = serverLogging
}
We pass these to the start method as part of a closure that the method then applies to the class before calling the setUp() and start() methods. Here are the implementation details:
public void start( closure ) {
this.with closure
validateConfig()
setUp()
grizzly.start()
}
The setUp() method then references these elements to set up the server appropriately, for example here's the logging section:
if( serverLogging ) {
servletRegistration.setInitParameter( "com.sun.jersey.spi.container.ContainerResponseFilters", "com.sun.jersey.server.linking.LinkFilter;com.sun.jersey.api.container.filter.LoggingFilter" )
servletRegistration.setInitParameter( "com.sun.jersey.spi.container.ContainerRequestFilters", "com.sun.jersey.api.container.filter.LoggingFilter" )
}
else {
servletRegistration.setInitParameter( "com.sun.jersey.spi.container.ContainerResponseFilters", "com.sun.jersey.server.linking.LinkFilter" )
}
Using this helper class makes our tests a lot easier to read and configure.