Introduction to MockServer
1. Overview
MockServer is a tool for mocking/stubbing external HTTP APIs.
2. Maven Dependencies
To make use of MockServer in our application, we need to add two dependencies:
<dependency> <groupId>org.mock-server</groupId> <artifactId>mockserver-netty</artifactId> <version>3.10.8</version> </dependency> <dependency> <groupId>org.mock-server</groupId> <artifactId>mockserver-client-java</artifactId> <version>3.10.8</version> </dependency>
The latest version of the dependencies is available as mockserver-netty and mockserver-client.
3. MockServer Functionality
Simply put, the tool can:
- generate and return fixed responses
- forward a request to another server
- execute callbacks
- verify a request
4. How to Run MockServer
We can start the server in a few different ways – let’s explore some of these methods.
4.1. Launching via Maven Plugin
This will launch the server during the process-test-class phase and stop at verify phase:
<plugin> <groupId>org.mock-server</groupId> <artifactId>mockserver-maven-plugin</artifactId> <version>3.10.8</version> <configuration> <serverPort>1080</serverPort> <proxyPort>1090</proxyPort> <logLevel>DEBUG</logLevel> <initializationClass>org.mockserver.maven.ExampleInitializationClass</initializationClass> </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>
4.2. Launching via Java API
We can use the startClientAndServer() Java API to start the server. Typically, we would start a server before running all tests:
public class TestMockServer { private ClientAndServer mockServer; @BeforeClass public void startServer() { mockServer = startClientAndServer(1080); } @AfterClass public void stopServer() { mockServer.stop(); } // ... }
5. Mock Clients
MockServerClient API is used for providing a capability to connect to the MockServer. It models requests and the corresponding responses from the server.
It supports multiple operations:
5.1. Creating Expectations With Mock Responses
Expectations are a mechanism by which we mock the request from a client and the resulting response from MockServer.
To create an expectation, we need to define a request matcher and a response that should be returned.
Requests can be matched using:
- path – URL path
- query string – URL parameters
- headers – request headers
- cookies – client side cookies
- body – POST request body with XPATH, JSON, JSON schema, regular expression, exact matching plain text or body parameters
All the above parameters can be specified using plain text or regular expressions.
And a response action will contain:
- status codes – valid HTTP status codes e.g. 200, 400 etc.
- body – it is the sequence of bytes containing any content
- headers – response headers with name and one or more values
- cookies – response cookies with name and one or more values
Let’s see how we can create an expectation:
public class TestMockServer { private void createExpectationForInvalidAuth() { new MockServerClient("127.0.0.1", 1080) .when( request() .withMethod("POST") .withPath("/validate") .withHeader("\"Content-type\", \"application/json\"") .withBody(exact("{username: 'foo', password: 'bar'}")), exactly(1)) .respond( response() .withStatusCode(401) .withHeaders( new Header("Content-Type", "application/json; charset=utf-8"), new Header("Cache-Control", "public, max-age=86400")) .withBody("{ message: 'incorrect username and password combination' }") .withDelay(TimeUnit.SECONDS,1) ); } // ... }
Here, we are stubbing a POST request to the server. And we have specified that how many times we need to make this request using exactly(1) call.
On receiving this request, we have mocked a response with the fields like status code, headers, and response body.
5.2. Forwarding a Request
Expectation can be set up to forward the request. A few parameters can describe the forward action:
- host – the host to forward to e.g. www.baeldung.com
- port – the port where the request to be forwarded, the default port is 80
- scheme – protocol to use e.g. HTTP or HTTPS
Let’s see an example of forwarding request:
private void createExpectationForForward(){ new MockServerClient("127.0.0.1", 1080) .when( request() .withMethod("GET") .withPath("/index.html"), exactly(1)) .forward( forward() .withHost("www.mock-server.com") .withPort(80) .withScheme(HttpForward.Scheme.HTTP) ); }
In this case, we have mocked a request which will hit the MockServer exactly ones and then forwarded to another server. The outer forward() method specifies the forward action and inner forward() method call helps constructing the URL and forwards the request.
5.3. Executing a Callback
The server can be set to execute a callback when receiving a particular request. Callback action can define callback class that implements org.mockserver.mock.action.ExpectationCallback interface. It should have the default constructor and should be on the classpath.
Let’s see an example of expectation with a callback:
private void createExpectationForCallBack() { mockServer .when( request().withPath("/callback")) .callback( callback() .withCallbackClass("com.baeldung.mock.server.TestExpectationCallback") ); }
Here the outer callback() specifies the callback action and the inner callback() method specifies the instance of the callback method class.
In this case, when MockServer receives a request with /callback, then the callback handle method implemented in the class specified will be executed:
public class TestExpectationCallback implements ExpectationCallback { public HttpResponse handle(HttpRequest httpRequest) { if (httpRequest.getPath().getValue().endsWith("/callback")) { return httpResponse; } else { return notFoundResponse(); } } public static HttpResponse httpResponse = response() .withStatusCode(200); }
5.4. Verifying Requests
MockServerClient has an ability to check if the system under test sent a request:
private void verifyPostRequest() { new MockServerClient("localhost", 1080).verify( request() .withMethod("POST") .withPath("/validate") .withBody(exact("{username: 'foo', password: 'bar'}")), VerificationTimes.exactly(1) ); }
Here, the org.mockserver.verify.VerificationTimes class is used to specify the number of times the Mock Server should match the request.
6. Conclusion
In this quick article, we have explored different functions of the MockServer. We have also explored the different APIs provided and how it can be used for testing complex systems.
As always, the complete code for this article is available over on GitHub.
Credits: https://www.baeldung.com/mockserver