Posts Tagged ‘webservices’

Lightweight testing of (webservice) HTTP clients with JUnit and Jetty

Posted in: , , , 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