Testing DropWizard Applications with Spock and Groovy

DropWizard is a really cool framework / library that allows you to quickly build production-ready HTTP+JSON REST services. It is built on mature libraries like Jetty, Jersey, Jackson and Metrics.

The framework bring together a lot of neat ideas for API monitoring like Health checks and simple application metrics via Metrics. DropWizard is very performant, claiming to be able to handle 15,000-20,000 requests per second. There is a pretty good video hailing the benefits of  DropWizard here. The MongoDB-DropWizard slideshow is also very good to see what is possible with the framework.

Compared to Grails, DropWizard feels slightly more lightweight and perfect for services that don’t really have much of a front-end. DropWizard and JavaScript fat clients is the new black.

In this post, I will share how you can use Spock and Groovy instead of the Java / JUnit / Mockito examples provided by the DropWizard User Manual.

If you are not familiar with DropWizard or the testing of DropWizard applications, I suggest reading their Quick Start Guide and User Manual. I will use the Representations and Resources in the Testing DropWizard chapter of their user guide as the basis for this post.

Installing Spock and Groovy

To start, you would want to install Spock and Groovy into your dropWizard application. You can do this in Maven, but we found that Gradle meets our needs better. You can download a sample Gradle build.gradle file for DropWizard here.

Testing DropWizard Representations

The test in JUnit / Mockito:

@Test
public void serializesToJSON() throws Exception {
    final Person person = new Person("Luther Blissett", "lb@example.com");
    assertThat("a Person can be serialized to JSON",
               asJson(person),
               is(equalTo(jsonFixture("fixtures/person.json"))));
}

In spock, we can use the same JsonHelpers provided by DropWizard for serializing and deserializing JSON. So the tests for representations are just a simple conversion.

def 'A person can be serialized to JSON'(){
    given:
        Person person = new Person("Luther Blissett", "lb@example.com")
    expect:
        asJson(person) == jsonFixture("fixtures/person.json") 
}

The deserialization is pretty much the same except that now we expect:

fromJson(jsonFixture("fixtures/person.json"), Person.class) == person)

One benefit of using spock here is simply that it is slightly less verbose and your tests are simpler to read.

For our project, we found that we don’t really need to use that many representations are we’re simply parroting other web services. We did discovered that it is quite difficult to get Jackson to handle Groovy classes, so keep your representations as Java classes in your projects will save you a lot of heart ache ( You can write everything else in Groovy ).

Testing DropWizard Resources

To test resources, DropWizard provides an in-memory Jersey server via the ResourceTest helper. Using this helper, you basically call a setUpResource method to add the resource under test, and then use the in-memory Jersey client to make sure everything works correctly:

    @Override
    protected void setUpResources() {
        when(store.fetchPerson(anyString())).thenReturn(person);
        addResource(new PersonResource(store));
    }

However, this helper is written with JUnit in mind and unusable for Spock. So we adapted it:


package resources

import com.yammer.dropwizard.testing.ResourceTest
import spock.lang.Shared
import spock.lang.Specification

abstract class ResourceSpec extends Specification {

   abstract void setUpResources()

   @Shared ResourceTest jersey = new ResourceTest() {
      @Override
      protected void setUpResources() {}
   }

   void setupSpec(){
      setUpResources()
      jersey.setUpJersey()
   }

   void cleanupSpec() {
      jersey.tearDownJersey()
   }

}

To use this in your tests, you extend the spec and provide a setUpResources method. One difference between the JUnit tests and this spec is that all the commands for ResourceTest such as addResource() and client() are called within the jersey property. ( I tried using @Delegate annotation for this, but it didn’t seem to work ).

So we can convert the following JUnit / Mockito example:

public class PersonResourceTest extends ResourceTest {
    private final Person person = new Person("blah", "blah@example.com");
    private final PeopleStore store = mock(PeopleStore.class);

    @Override
    protected void setUpResources() {
        when(store.fetchPerson(anyString())).thenReturn(person);
        addResource(new PersonResource(store));
    }

    @Test
    public void simpleResourceTest() throws Exception {
        assertThat("GET requests fetch the Person by ID",
                   client().resource("/person/blah").get(Person.class),
                   is(person));

        verify(store).fetchPerson("blah");
    }
}

to one that uses Spock mocks and the Resource Spec as follows:

class PersonResourceSpec extends ResourceSpec {
    @Shared Person person    
    @Shared PeopleStore store 

    @Overide void setUpResources(){
        person = new Person("blah", "blah@example.com") 
        store = Mock(PeopleStore){
            1 * fetchPerson('blah') >> person
        } 
        jersey.addResource(new PersonResource(store))
    }

    def 'GET requests fetch the Person by ID'(){
        expect:
            jersey.client().resource('/person/blah').get(Person) == person    
    }
}

In this example, we created a Spock Mock for PeopleStore and defined an interaction for the fetchPerson method.

Since setUpResources is called within the setupSpec section of the Specification, we can create these type of interactions.

You will also notice that instead of addResource() and client() in the JUnit/Mockito example, we use jersey.addResource() and jersey.client().

We did run into difficulties setting interactions within test when using the in-memory Jersey server. If we didn’t provide an interaction to the Mock and then try to add it later, i.e,

    def 'GET requests fetch the Person by ID'(){
        given:
            1 * store.fetchPerson( 'blah' ) >> person  // totally valid in Spock
        expect:
            jersey.client().resource('/person/blah').get(Person.class) == person    
    }

this would result in a MissingMethodException. We suspect it has to do with the way in which the in-memory jersey server in dropwizard gets passed the mocked instance. Constructing the Mock with interactions and adding it as a jersey resource made the problem go away.

As a user of DropWizard, I wish the testing support for adding and removing the in-memory Jersey server was agnostic to the test implementation.

I encourage you to start playing with DropWizard as it is a much lighter framework in the vein of other microframeworks like Ratpack, Caelyf and Gaelyk for Groovy. Given it’s focus on performance and REST-friendliness, it’s quite awesome.

2 thoughts on “Testing DropWizard Applications with Spock and Groovy

  1. Pingback: Choosing DropWizard to deliver content within your Grails projects | Tomás Lin's Programming Brain Dump

  2. edovale

    “As a user of DropWizard, I wish the testing support for adding and removing the in-memory Jersey server was agnostic to the test implementation.”

    The DropwizardAppRule class is fairly agnostic to the test framework. In you spock specification you can instantiate it and call the method before and after from the setupSpec and cleanupSpec method of your specification. This works fine.

    Reply

Leave a comment