Posts Tagged ‘webservices’
Lightweight testing of (webservice) HTTP clients with JUnit and Jetty
Wednesday, July 14th, 2010
Posted in: http clients, junit, test, webservices J2EE, java, maven 2, open source.
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.
5 Comments