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.

Tagged with →  
Share →

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

  1. Jeremy says:

    Hi Olaf –

    My company found this extremely useful in unit testing Android applications.

  2. Chris de Groot says:

    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.

  3. olaf says:

    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

  4. [...] 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 [...]

  5. Neville says:

    This looks like exactly what I was thinking about needing to create. I think it will be very useful.
    Unfortunately the zip contains no maven2 pom. Since the link was described as maven 2 project I was expecting a pom. Would it be possible for you to at least list the dependencies or upload the pom.

  6. [...] Lightweight testing of (webservice) HTTP clients with JUnit and Jetty. Article in Olaf’s blog. This entry was posted in Link and tagged java, jetty, junit. Bookmark the permalink. ← dbox – Instagram Filters as Photoshop Actions [...]

  7. Dave says:

    hi olaf,
    in my project what i need to do is, i need to send some infos to other service through the WS, will get the response from that server according to the data that i’ve sent… i really cant do anything for the junit Mock testing!! um scratching my head for last 3 days but wasnt able to do the testing!! cld u plz help me on that?? thnx in advance..

    • olaf says:

      Hi Dave

      Well, sending a request to a service and getting the response is pretty much what WS are about :-) I assume you are talking about a SOAP-based web service which has a WSDL and a client build according this WSDL (e.g. generated using Axis).

      I suggest you identify the use cases here (i.e., types of service invocations and responses, for instance submitting an order, once with a successful result and once with a failre response). Then, invoke the real service and record the service response (e.g. using wireshark). Afterwards, proceed as mentioned in this post, i.e. use the recorded XML reponses to mock up the service.

      A different – but more generic – solution is to use Soap UI. This tool also features extensive generation and execution of test cases.

  8. [...] here is the code for this mock server, it the same as the Lightweight testing of webservice with jetty with some small [...]

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>