Lightweight testing of (webservice) HTTP clients with JUnit and Jetty
If you’re working with webservice clients you will certainly have noticed the complexity of integration-testing your webservice clients. Building webservice clients can already be quite a complex task, but providing a mock-up webservice backend delivering useful test responses is quite often just to much work, if not impossible, since many web service backends are very complex constructs. Furthermore, setting up a backend for each integration test consumes valuable build time.
As an alternative, one may simply replace the backend with a mock HTTP server that does one thing: deliver the expected webserver response – i.e. XML data – when called by the client. All you need to set this up is a HTTP server and a pre-recorded service response (quite often this comes with WS client specifications). If you don’t have this data, you can record it, for example using a proxy server in between your WS client and a real WS backend, or a tool such as wireshark.
The recorded XML response thus represents your assumptions against which you test the client. This makes your tests fast, lightweight and a lot better to understand.
Here is my Jetty-based test HTTP server:
package de.sysbsb.test;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.apache.commons.io.IOUtils.write;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.junit.Ignore;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.HttpConnection;
import org.mortbay.jetty.Request;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.AbstractHandler;
/**
* A server for answering HTTP requests with test response data.
*
* @author Olaf Otto
*/
@Ignore
public class HttpTestServer {
public static final int HTTP_PORT = 50036;
private Server _server;
private String _responseBody;
private String _requestBody;
private String _mockResponseData;
public HttpTestServer() {
}
public HttpTestServer(String mockData) {
setMockResponseData(mockData);
}
public void start() throws Exception {
configureServer();
startServer();
}
private void startServer() throws Exception {
_server.start();
}
protected void configureServer() {
_server = new Server(HTTP_PORT);
_server.setHandler(getMockHandler());
}
/**
* Creates an {@link AbstractHandler handler} returning an arbitrary String as a response.
*
* @return never <code>null</code>.
*/
public Handler getMockHandler() {
Handler handler = new AbstractHandler() {
public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException {
Request baseRequest = request instanceof Request ? (Request) request : HttpConnection.getCurrentConnection().getRequest();
setResponseBody(getMockResponseData());
setRequestBody(IOUtils.toString(baseRequest.getInputStream()));
response.setStatus(SC_OK);
response.setContentType("text/xml;charset=utf-8");
write(getResponseBody(), response.getOutputStream());
baseRequest.setHandled(true);
}
};
return handler;
}
public void stop() throws Exception {
_server.stop();
}
public void setResponseBody(String responseBody) {
_responseBody = responseBody;
}
public String getResponseBody() {
return _responseBody;
}
public void setRequestBody(String requestBody) {
_requestBody = requestBody;
}
public String getRequestBody() {
return _requestBody;
}
public static void main(String[] args) {
HttpTestServer server = new HttpTestServer();
try {
server.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void setMockResponseData(String mockResponseData) {
_mockResponseData = mockResponseData;
}
public String getMockResponseData() {
return _mockResponseData;
}
protected Server getServer() {
return _server;
}
}
You can use it in a JUnit test like so:
package de.sysbsb.test;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* @author Olaf Otto
*/
public class MyClientTest {
private HttpTestServer _server;
@Before
public void startTestServer() throws Exception {
_server = new HttpTestServer();
_server.start();
}
@After
public void stopTestServer() throws Exception {
_server.stop();
}
@Test
public void someClientTest() throws IOException {
_server.setMockResponseData("<xml><testdata>hello, world</testdata></xml>");
// or as a much more elegant alternative:
_server.setMockResponseData(getRecordedResponse("testdata.xml"));
// run your client tests, using the HttpTestServer.HTTP_PORT
}
private String getRecordedResponse(String recordedResponseFile) throws IOException {
InputStream testDataStream = getClass().getClassLoader().getResourceAsStream(recordedResponseFile);
return IOUtils.toString(testDataStream);
}
}
Here are is the HTTP test server and a JUnit test example as a maven 2 project.
This entry was posted on Wednesday, July 14th, 2010 at 08:48. Posted in: http clients, junit, test, webservices J2EE, java, maven 2, open source. You can follow any responses to this entry through the RSS 2.0feed. You can leave a response, or trackback from your own site.

Hi Olaf –
My company found this extremely useful in unit testing Android applications.
Hi Olaf,
so I like this, but what I’m looking for is something that reliably and reproducibly creates bad responses. For example unexpected redirects, waits, truncated responses, returns null, never returns etc. I want an automatic web service from hell. Any idea if someone has written that already?
many thanks C.
Hi Chris
I am wondering what the application of such a tool may be – perhaps testing the handling of syntactically invalid responses of a completely custom WS client?
Unfortunately I have not heard about a tool capabale of what you need (did you find anything in the meantime?). I’m also wondering if you’d really need that – on the protocol level, TCP will handle connection issues such as timeouts. HTTP provides serverside status information. Syntactically invalid responses will be detectet when unmarshalling the data in the client as it must conform to the schema provided with the WSDL. All of these issues will lead to an Exception (at least using the common WS client implementations). The only scenario I can think of is semantically invalid responses from some kind of really bad web service that does not make any guarantee as to what the DTOs will contain. In the latter case unmarshalling to a bean and validating it (e.g. using JSR-303 bean validation) would be a solution.
Anyway, if you really need a penetration test, writing something like a random response generator / fuzzer yourself and recording it’s responses in a sort of script / log file for replay is the thing I’d probably do. However, it will be impossible to cover all possible variants of erroneous responses imo.
Best,
Olaf
[...] Hope it helps somebody else too. Cheers! [1] http://martinfowler.com/bliki/TestDouble.html2 http://olafsblog.sysbsb.de/lightweight-testing-of-webservice-http-clients-with-junit-and-jetty This entry was posted on Sunday, October 23rd, 2011 at 10:10 PM and is filed under Blog, [...]
[...] a look at http://olafsblog.sysbsb.de/lightweight-testing-of-webservice-http-clients-with-junit-and-jetty/. It’s brilliant, basically what you do is you start up Jetty internally in your test class [...]