Testing and Mocking Jersey Responses

jersey

Jersey is a decent reference implementation of the Java REST WebServices API. It comes with server, client and test libraries. If in doubt, you use jersey test to host your endpoint and use the client that comes with jersey test to reach that endpoint.

This is a good system for testing the behaviour of a server endpoint. It’s a bit more problematic if you are trying to test client-side jersey behaviour. If you want to mock out an external REST service and see how your client responds to it, you have a problem.

Imagine a client attempting to do this:

Response response = clientCaller.getEndpointResponse();
SomePojo pojo = response.readEntity(SomePojo.class);

You could reasonably assemble the response for the above like this:

// in Fake client caller
Response fakeResponse = Response.ok(new SomePojo("data"))
  .build();
return fakeResponse;

One annoying problem. The response produced by Response.build() is Outbound and your client needs an Inbound response.

The entity in the outbound response is a Java object. You can get it with getEntity and cast it to the type you want, but your client can’t do that at production time. The inbound response holds a serialized version of the entity which readEntity deserializes. This happens at production time after the outbound response is serialized and sent down the wire to a client which produces the inbound response.

However, at test time you can mock your way out of this.

The following routine will convert a response produced using Response.build() into something which supports readEntity.

/**
* Turn a locally made {@link Response} into one which
* can be used as though inbound.
* This enables readEntity to be used on what should 
* be an outbound response
* outbound responses don't support readEntity, but we
* can fudge it using mockito.
* @param asOutbound response built as though being sent
*   to the received
* @return a spy on the response which adds reading 
* as though inbound
*/
public static Response simulateInbound(Response asOutbound) {

  Response toReturn = spy(asOutbound);

  // answer() in Mockito2 - AdditionalAnswers
  doAnswer(answer((Class type) -> readEntity(toReturn, type)))
    .when(toReturn)
    .readEntity(ArgumentMatchers.<Class<?>>any());
  return toReturn;
}

// use the getEntity from the real object as
// the readEntity of the mock
@SuppressWarnings("unchecked")
private static <T> T readEntity(Response realResponse, Class<T> t) {
  return (T)realResponse.getEntity();
}

5 comments

  1. Sorry. I think this wold solve exactly my trouble trying to mock a service with JSON Response.
    But in your code snippet ‘readEntity(toReturn, type)’ the compiler says: Cannot resolve method ‘readEntity’ in ‘ActualClass’.

    • Yes. I saw this code snippet on StackOverflow the other day and couldn’t quite remember what I meant by it. I think the idea is that you create the `readEntity` function yourself.

      I’ve now extended the example to show it. Sorry for missing it in the first place.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s