Mocking HTTP Interaction with Java, JUnit and MockServer

January 5th, 2016 by

When writing tests for our software components sometimes we need to mock external services based on the HTTP protocol, might it be a RESTful web-service, an XML-RPC call or a simple GET request to some web-server.

In the following short tutorial I’d like to demonstrate how to create a mock HTTP server for testing and how to bootstrap and bind it to the life-cycle of a classical build-management tool like Maven.

Running a Mockserver JUnit Test in Eclipse IDE.

Running a Mockserver JUnit Test in Eclipse IDE.

 

Dependencies

We just need to add two dependencies to our pom.xml:

  • JUnit as test framework and
  • Netty as our web-server implementation.
<dependency>
	<groupId>org.mock-server</groupId>
	<artifactId>mockserver-netty</artifactId>
	<version>3.10.2</version>
	<scope>test</scope>
</dependency>
<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.12</version>
	<scope>test</scope>
</dependency>

JUnit Rule

Starting our mock HTTP server is quite easy as we’re just using a JUnit role here to bootstrap the server.

In the following example, we’re bootstrapping an instance to run on port 9000 and to return a HTTP status code of 200 when the URL part “/foo” is called.

Afterwards we’re using a standard JAX-RS client to send a request to the HTTP server and we’re verifying that the response status is 200.

In the last step, the mock-server-client allows us to verify that the mock-server has received exactly one request for “/foo”.

package it;
 
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
 
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Response;
 
import org.junit.Rule;
import org.junit.Test;
import org.mockserver.client.server.MockServerClient;
import org.mockserver.junit.MockServerRule;
import org.mockserver.model.HttpRequest;
import org.mockserver.model.HttpResponse;
import org.mockserver.verify.VerificationTimes;
 
public class HttpTest {
	@Rule
	public MockServerRule mockServerRule = new MockServerRule(this, 9000);
 
	private MockServerClient mockServerClient;
 
	@Test
	public void shouldConnectToHttpService() throws Exception {
		// setting behaviour for test case
		mockServerClient.when(HttpRequest.request("/foo")).respond(HttpResponse.response().withStatusCode(200));
 
		// create a GET request using JAX-RS rest client API
		Client client = ClientBuilder.newClient();
		Response response = client.target("http://localhost:9000").path("/foo").request().get();
 
		// assert response
		assertThat(response.getStatus(), equalTo(200));
 
		// verify server has received exactly one request
		mockServerClient.verify(HttpRequest.request("/foo"), VerificationTimes.once());
	}
}

We may now run our tests in our IDE using the JUnit runner or using Maven like this:

$ mvn test
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running it.HttpTest
[..]
17:17:15.383 [MockServer thread for port: 9000] DEBUG i.n.util.internal.ThreadLocalRandom - -Dio.netty.initialSeedUniquifier: 0x373b4db8098b0b21 (took 8 ms)
17:17:15.531 [main] DEBUG o.m.client.netty.NettyHttpClient - Sending request: {
  "method" : "PUT",
  "path" : "/expectation",
  "body" : {
    "charset" : "UTF-8",
    "type" : "STRING",
    "string" : "{\n  \"httpRequest\" : {\n    \"path\" : \"/foo\"\n  },\n  \"httpResponse\" : {\n    \"statusCode\" : 200\n  },\n  \"times\" : {\n    \"remainingTimes\" : 0,\n    \"unlimited\" : true\n  },\n  \"timeToLive\" : {\n    \"unlimited\" : true\n  }\n}"
  }
}
[..]
17:17:15.755 [nioEventLoopGroup-3-1] INFO  o.m.mockserver.MockServerHandler - creating expectation:
 
        {
          "httpRequest" : {
            "path" : "/foo"
          },
          "times" : {
            "remainingTimes" : 0,
            "unlimited" : true
          },
          "timeToLive" : {
            "unlimited" : true
          },
          "httpResponse" : {
            "statusCode" : 200
          }
        }
[..]
17:17:16.018 [nioEventLoopGroup-3-2] INFO  o.m.matchers.HttpRequestMatcher - request:
 
        {
          "method" : "GET",
          "path" : "/foo",
          "headers" : [ {
            "name" : "User-Agent",
            "values" : [ "Jersey/2.5 (HttpUrlConnection 1.8.0_45)" ]
          }, {
            "name" : "Host",
            "values" : [ "localhost:9000" ]
          }, {
            "name" : "Accept",
            "values" : [ "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2" ]
          }, {
            "name" : "Connection",
            "values" : [ "keep-alive" ]
          }, {
            "name" : "Content-Length",
            "values" : [ "0" ]
          } ],
          "keepAlive" : true,
          "secure" : false
        }
[..]
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.067 sec
[..]
Results :
 
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

Maven Lifecycle Integration

The Maven plug-in allows us boot mock server instances when a specific Maven life-cycle phase is reached as in the following example (I have used a Maven profile named “start-mockserver” here to explicitly start the mock-server when this Maven profile is used..):

<profile>
	<id>start-mockserver</id>
	<activation>
		<activeByDefault>false</activeByDefault>
	</activation>
	<build>
		<plugins>
			<plugin>
				<groupId>org.mock-server</groupId>
				<artifactId>mockserver-maven-plugin</artifactId>
				<version>3.10.1</version>
				<configuration>
					<serverPort>9000</serverPort>
					<proxyPort>9000</proxyPort>
					<logLevel>DEBUG</logLevel>
				</configuration>
				<executions>
					<execution>
						<id>process-test-classes</id>
						<phase>process-test-classes</phase>
						<goals>
							<goal>start</goal>
						</goals>
					</execution>
					<execution>
						<id>verify</id>
						<phase>verify</phase>
						<goals>
							<goal>stop</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</profile>

To boot the mock server, we now just need to run our tests with this specific profile:

mvn -Pstart-mockserver test

Tutorial Sources

Please feel free to download the tutorial sources from my Bitbucket repository, fork it there or clone it using Git:

git clone https://bitbucket.org/hascode/mockserver-junit-tutorial.git

Resources

Other Testing Tutorials of mine

Tags: , , , , , , , , , , , ,

3 Responses to “Mocking HTTP Interaction with Java, JUnit and MockServer”

  1. Emilie Says:

    Thanks for the complete tutorial!!

  2. Micha Kops Says:

    Hi Emilie,

    thanks, you’re welcome! :)

  3. santosh barik Says:

    Hi,
    I am facing some issues while writing the test cases for JAX-RS Rest Client.
    In Rest there will be 2 ends one is Rest Resource(Rest Service) and Rest Client who will consume the Rest Resource. I have developed the code for Rest Client which is working fine. But I don’t understand how to write the JUnit Test cases for this client code. because the output from the rest resource is the hashcode of object which will be unique and for every time when my client will make the HTTP call it will be different so so how I will write the test cases for my rest client.
    and for this do I need to create a different rest resource or the same rest resource will be used for testing the rest client code and one more thing suppose if I will create one different rest resource for testing the rest client then how this rest resource will be up and running for each time when i will test my rest client or do I need to keep this rest resource up and running.
    Please give me some idea around it as soon as possible.

Search
Categories