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;
  }
Advertisements

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