Sunday, July 8, 2012

Unit Testing REST with Jersey and AppEngine

I have read many articles about Unit Testing REST and JSON including much examples. I have been guided to use Grizzly or another webserver to test if REST is working on the Jersey Website. They load and stop the webcontainer over the @Before and @After annotations. I have tried that using the Datastore with AppEngine but it didn't work. Reason was that the webservers are spawning multiple threads which is not allowed in the AppEngine Development environment. The problem is that the threaded webservers will not find the datastore that is created during tests. I also tried to use the Jersey Test Framework which has not played nicely together with AppEngine out of the same reasons.

I have created a post on Stackoverflow and got the answer, that first of all using a webserver is rather considered as an Integration Test not a Unit Test and that it makes sense in AppEngine to execute the method in the resources class directly for testing purposes. During my studies how to accomplish this I have noticed however that when I use the Response class I can't seem to get back an entity using the getEntity() method in my test class. When debugging I could see that the response contained the content of the object but I was unable to get the content using the getEntity() method from the Response class. So I made another post on Google Groups and got the answer that I could Mock the response.

I didn't try mocking yet and went directly to the integration testing by starting up the development environment because I wanted to see if it works first when I use the ClientResponse class to get the JSON response in to my Card object. And it worked. So my current suggestion on this is to start the webserver for the REST tests. I may try mocking once I have some time.

Here a create example:

CardResource class:
@Path("/card")
public class CardResource {
    CardDAO dao = new CardDAO();

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response create(Card card) {
        Card c = dao.create(card);
        if(c.equals(null)) {
            return Response.status(Status.BAD_REQUEST).entity("Create failed!").build();
        }
       
        return Response.status(Status.OK)
                .entity(c)
                .type(MediaType.APPLICATION_JSON)
                .build();
    }
}

CardResourceTests class (Junit):
public class CardResourceTests {   
    @Test
    public void testCreate() throws Exception {
        Client client = Client.create();
        WebResource webResource = client.resource("http://localhost:8888/api/card");
       
        Card c = new Card(1, "Cardname", "12345678", 1, 1,
                "cardname.jpg", new Date(), new Date());         
       
        ClientResponse s = webResource.type(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .post(ClientResponse.class, c);
       
        Card r = (Card)s.getEntity(Card.class);
       
        assertEquals("Result", r.getName(), "Cardname");
    }
}