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.

mockserver junit test in eclipse 1024x759

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 GitHub repository, fork it there or clone it using Git:

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