implements Elegance {

// Elwyn Malethan's musings on software development, mountain biking and general navel–gazing...

Articles tagged with 'httpclient'

Unit testing with Commons HttpClient

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.

private static Action willRespondWith(final int code, final String status, final String body) {
    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:

@Test
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.