I‘ve been adding some test coverage to some existing code today. This code under test uses Commons HTTP Client to fetch data from an external resource. I ran into problems with mocking/stubbing the response to the HTTP requests.
I am not the only one who has faced problems with this Http Client. In that article, Florin provides a good solution using a concrete subclass of HttpClient in order to mock it‘s behaviour. His article was very useful in helping me formulate my approach.
I use JMock for dynamic mock objects and so I was keen not to have to mix of JMock-based mocks and concrete mock objects. So my approach is to use JMock‘s custom actions to provide an implementation that populates the right values in the right way. Although, I had to use some reflective cheating to set the necessary values.
return new CustomAction("will respond with status: " + code + ", and contents: " + body) {
@Override
public Object invoke(Invocation invocation) throws Throwable {
final Object method = invocation.getParameter(0);
final Field statusLine = HttpMethodBase.class.getDeclaredField("statusLine");
statusLine.setAccessible(true);
statusLine.set(method, new StatusLine("HTTP/1.0 " + code + " " + status)); //Although, 'OK' could be anything
final Method setResponseStream = HttpMethodBase.class.getDeclaredMethod("setResponseStream", InputStream.class);
setResponseStream.setAccessible(true);
setResponseStream.invoke(method, new ByteArrayInputStream(body.getBytes("UTF-8")));
return code;
}
};
}
This is intended to be used as follows:
public void testSomeHttpStuff() throws Exception {
jmock.checking(new Expectations() {{
allowing(client).executeMethod(with(any(HttpMethod.class)));
will(willRespondWith(200, "OK", "{some: 'value'}"));
}});
sendHttpRequest("http://some.server/some/resource.json");
}
Now I can simulate all sorts of responses from the external resource.
First published on Apr 26, 2010. Last updated on: Apr 26, 2010.