What is MockServer
MockServer can be used for mocking any system you integrate with via HTTP or HTTPS (i.e. services, web sites, etc).
MockServer can:
- return a "mock" response when a request matches an expectation (see more below)
- forward a request when the request matches an expectation (i.e. ack as a selective proxy) (see more below)
- execute a callback (in Java) when a request matches an expectation, allowing the response to be created dynamically (see more below)
- verify requests have been sent (i.e. in a test assertion) (see more below)
What is MockServer Proxy
MockServer Proxy can be used for transparently recording all requests sent by a system (i.e. an application or a set of applications and servers).
MockServer Proxy can:
- proxy all requests using port forwarding, HTTP proxying, HTTPS proxying (HTTP CONNECT), and SOCKS proxying
- verify requests have been sent (i.e. in a test assertion) (see more)
- record requests and responses to analyse how a system behaves (see more)
The different proxying methods are:
- port forwarding
- all requests for a specific local port are forwarded to a different (local or remote) port and hostname
- no client or operating system configuration required
- HTTP proxy
- all requests are forwarded using the Host header of the HTTP request
- the client must be configured to use the proxy
- HTTPS proxy
- all requests are forwarded using a CONNECT request
- the client must be configured to use the proxy
- SOCKS proxy
- all requests are forwarded to port and hostname when socket connection is created
- the operating system (or JVM) must be configured to use the proxy
- SSL & Certificates
- all SSL traffic is handled transparently by auto-generating an appropriate SSL certificate using a single MockServer root CA certificate
MockServer & MockServer Proxy Clients:
There are currently clients written in Java, JavaScript and Ruby (see more below) although any language that can send JSON via HTTP can easily use the MockServer Web API.
- Java
- JavaScript (browser API & Node.js)
- Ruby
Why use MockServer
MockServer allows you to mock any server or service that you connect to over HTTP or HTTPS, such as a REST or RPC service.
This is useful in the following scenarios:
- testing
- easily recreate all types of responses for HTTP dependencies such as REST or RPC services to test applications easily and affectively
- isolate the system under test to ensure tests run reliably and only fail when there is a genuine bug. It is important only the system under test is tested and not its dependencies to avoid tests failing due to irrelevant external changes such as network failure or a server being rebooted / redeployed.
- easily setup mock responses independently for each test to ensure test data is encapsulated with each test. Avoid sharing data between tests that is difficult to manage and maintain and risks tests infecting each other.
- de-coupling development
- start working against a service API before the service is available. If an API or service is not yet fully developed MockServer can mock the API allowing any team who is using the service to start work without being delayed.
- isolate development teams particularly critical during the initial development phases when the APIs / services may be extremely unstable and volatile. Using MockServer allows development work to continue even when an external service fails.
A system with service dependencies as follows:
MockServer could be used to mock the service dependencies, as follows:
Why use MockServer Proxy
MockServer proxy allows you to record requests from the system-under-test or to analysis an existing system by recording outbound requests.
This is useful in the following scenarios:
- testing
- create test assertions that verify the requests the system-under-test has been sent, without needing to mock any requests
- analyse existing system
- record all outbound requests so it is possible to analise and under stand what outbound requests an existing system is making
- record & replay
- all recorded requests can be converted into Java code or JSON expectations to simplify the creation of mocks for complex test scenarios
MockServer Proxy could be used to verify service requests, as follows:
Getting Started
To use MockServer:
Mocking Overview
To mock an HTTP / HTTPS interaction an expectation is setup specifying how a request should be matched and what action MockServer should take with when the request has been matched.
When a request is matched there are three actions that can be defined as follows:
- respond - return a "mock" response
- forward - forward the request
- callback - execute a callback
For example to create an expectation using Java then has a respond action:
new MockServerClient("localhost", 9999)
.when(
request()
.withMethod("POST")
.withPath("/login")
.withQueryStringParameters(
new Parameter("returnUrl", "/account")
)
.withCookies(
new Cookie("sessionId", "2By8LOhBmaW5nZXJwcmludCIlMDAzMW")
)
.withBody("{username: 'foo', password: 'bar'}"),
Times.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(new Delay(TimeUnit.SECONDS, 1))
);
Or to create an expectation using JavaScript:
mockServerClient("http://localhost:9999").mockAnyResponse({
"httpRequest": {
"method": "POST",
"path": "/login",
"queryStringParameters": [
{
"name": "returnUrl",
"values": ["/account"]
}
],
"cookies": [
{
"name": "sessionId",
"values": ["2By8LOhBmaW5nZXJwcmludCIlMDAzMW"]
}
],
"body": {
"type": "JSON",
"value": JSON.stringify({ username: "foo", password: "bar" })
}
},
"httpResponse": {
"statusCode": 401,
"headers": [
{
"name": "Content-Type",
"values": ["application/json; charset=utf-8"]
},
{
"name": "Cache-Control",
"values": ["public, max-age=86400"]
}
],
"body": JSON.stringify({ message: "incorrect username and password combination" }),
"delay": {
"timeUnit": "SECONDS",
"value": 1
}
},
"times": {
"remainingTimes": 1,
"unlimited": false
}
});
Requests can be matched on:
- path - regex or plain text
- query string - regex or plain text
- headers - regex or plain text
- cookies - regex or plain text
- body - XPath, json, regex, plain text (exact match), or body parameters
The body can be matched using plain text, a json expression, an XPath expression or a regular expression, see XPath Expression Syntax for supported XPath syntax.
All other matching can be done using plain text or a regular expression, see Pattern (Java Platform SE 6) for supported regular expression syntax.
For more details see the section below on creating expectations.
Actions can be defined:
When a request is matched there are three actions that can be defined as follows:
- respond - return a "mock" response
- forward - forward the request
- callback - execute a callback
Respond Actions
A response action defines a mock response. Each response can contain:
- status code
- body
- headers
- cookies
Responses can be further controlled using:
- a delay before the response is sent
- the number of times the response is sent (including unlimited)
For more details see the section below on creating expectations.
Forward Actions
A forward action defines how a request should be forwarded. Each forward can contain:
- host
- port
- scheme
Only the host is mandatory as the port is default to 80 and the scheme is defaulted to HTTP.
For more details see the section below on creating expectations.
Callback Actions
A callback action defines a class that will be used to dynamically generate the response. Each callback contains:
- callbackClass
The class must define a default constructor and implement org.mockserver.mock.action.ExpectationCallback.
For more details see the section below on creating expectations.
Proxying Overview
MockServer also provides an HTTP / HTTPS proxy that can be used to record requests / responses.
Once requests / responses have been recorded:
- They can be queried pragmatically to confirm what requests have been sent and what responses have been received.
- This supports test assertions that confirm what requests the system-under-test has been sending during a test.
- They can be output in JSON format to log what request the system under has sent and what responses it received.
- This is useful for analysing an existing system prior to writing automated tests.
- This is also useful to simplify the creation of test setup code as the JSON output is in MockServer expectation format.
- They can be output in human readable Java code format that can be pasted directly into a test setup method.
- This is useful to simplify the creation of expectations in test setup methods as the code can be easily pasted directly into a test setup method and then modified as appropriate for the needs of the test scenario.
For example to use the proxy to verify a request has been sent:
new ProxyClient("localhost", 9999)
.verify(
request()
.withMethod("POST")
.withPath("/login")
.withBody("{username: 'foo', password: 'bar'}"),
VerificationTimes.exactly(1)
);
For example to use the proxy to print recorded requests and response to the log as JSON:
new ProxyClient("localhost", 9999)
.dumpToLogAsJSON(
request()
.withPath("/login")
);
This would result in entries in the mockserver_request.log file of the following format:
2014-01-11 13:08:54,225 {
"httpRequest": {
"method": "POST",
"path": "/login",
"body": {
"type": "STRING",
"value": "{username: 'foo', password: 'bar'}",
},
"cookies": [
{
"name": "sid",
"values": [ "05F1A3D2F2143C49727" ]
}
],
"headers": [
{
"name": "Accept-Language",
"values": [ "en-US,en;q=0.8,fa;q=0.6" ]
},
{
"name": "Cookie",
"values": [ "sid=05F1A3D2F2143C49727" ]
},
{
"name": "Host",
"values": [ "localhost:2021" ]
},
{
"name": "Content-Length",
"values": [ "34" ]
},
{
"name": "Accept-Encoding",
"values": [ "gzip,deflate,sdch" ]
},
{
"name": "User-Agent",
"values": [ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36" ]
},
{
"name": "Accept",
"values": [ "*/*" ]
},
{
"name": "Content-Type",
"values": [ "text/plain" ]
}
]
},
"httpResponse": {
"statusCode": 200,
"body": "{ message: 'success' }",
"headers": [
{
"name": "Content-Type",
"values": [ "application/json; charset=utf-8" ]
},
{
"name": "Cache-Control",
"values": [ "no-cache, no-store" ]
}
]
},
"times": {
"remainingTimes": 1,
"unlimited": false
}
}
MockServer & Proxy Versions
MockServer is flexible and support numerous usage patterns.
The mock server can be run:
- via the mockserver-maven-plugin, for example, as part of a build cycle
- programmatically via an API, for example, in an @Before / @After method
- from the command line as a stand-alone process, for example, as part of a deployment process to a test environment
- from a Grunt build using a Grunt plugin
- from an Node.js code using an npm plugin
MockServer is available as:
- a stand alone Netty web server that is fully self contained
- a deployable WAR that runs on any JEE web server
- a Vert.X module that runs on a Vert.X
- a Grunt plugin (that has the embedded Netty server bundle with it)
- an npm plugin (that has the embedded Netty server bundle with it)
Clients
MockServer has the following clients:
Note: It is not necessary to use the provided clients because the protocol is very simple JSON/HTTP.
- Java
- org.mockserver.client.server.MockServerClient - supports:
- creating expectations
- clearing expectations (selectively)
- resetting (clearing all expectations)
- dumping all expectations to the log (for debugging)
- verifying which requests have been received
- org.mockserver.client.proxy.ProxyClient - supports:
- verifying which requests have been recorded
- retrieving all recorded requests / responses as JSON or Expectation objects
- outputting to the log all recorded requests / responses as Expectations in JSON format
- outputting to the log all recorded requests / responses as Expectations in Java code format that can be pasted into test setup methods
- clearing recorded requests / responses (selectively)
- resetting (clearing all recorded requests / responses)
- org.mockserver.client.server.MockServerClient - supports:
- JavaScript (both browser API & Node.js module)
- mockServerClient - supports:
- creating expectations
- clearing expectations (selectively)
- resetting (clearing all expectations)
- dumping all expectations to the log (for debugging)
- verifying which requests have been received
- proxyClient - supports:
- verifying which requests have been recorded
- retrieving all recorded requests / responses as JSON or Expectation objects
- outputting to the log all recorded requests / responses as Expectations in JSON format
- clearing recorded requests / responses (selectively)
- resetting (clearing all recorded requests / responses)
- mockServerClient - supports:
Java MockServer Client
To simplest way to interact with MockServer from Java is to use org.mockserver.client.server.MockServerClient which provides the following API:
public class MockServerClient {
/**
* Start the client communicating to a MockServer at the specified host and port
* for example:
*
* MockServerClient mockServerClient = new MockServerClient("localhost", 8080);
*
* @param host the host for MockServer to communicate with
* @param port the port for MockServer to communicate with
*/
public MockServerClient(String host, int port);
/**
* Start the client communicating to a MockServer at the specified host and port
* and contextPath for example:
*
* MockServerClient mockServerClient = new MockServerClient("localhost", 8080);
*
* @param host the host for MockServer to communicate with
* @param port the port for MockServer to communicate with
* @param contextPath the context path that MockServer war is deployed to
*/
public MockServerClient(String host, int port, String contextPath);
/**
* Specify an unlimited expectation that will respond regardless of the number of matching http
* for example:
*
* mockServerClient
* .when(
* request()
* .withPath("/some_path")
* .withBody("some_request_body")
* )
* .respond(
* response()
* .withBody("some_response_body")
* .withHeaders(
* new Header("responseName", "responseValue")
* )
* );
*
* @param httpRequest the http request that must be matched for this expectation to respond
* @return an Expectation object that can be used to specify the response
*/
public ForwardChainExpectation when(HttpRequest httpRequest);
/**
* Specify an limited expectation that will respond a specified number of times when the http is matched
* for example:
*
* mockServerClient
* .when(
* new HttpRequest()
* .withPath("/some_path")
* .withBody("some_request_body"),
* Times.exactly(5)
* )
* .respond(
* new HttpResponse()
* .withBody("some_response_body")
* .withHeaders(
* new Header("responseName", "responseValue")
* )
* );
*
* @param httpRequest the http request that must be matched for this expectation to respond
* @param times the number of times to respond when this http is matched
* @return an Expectation object that can be used to specify the response
*/
public ForwardChainExpectation when(HttpRequest httpRequest, Times times);
/**
* Pretty-print the json for all expectations to the log. They are printed into a dedicated log called mockserver_request.log
*/
public MockServerClient dumpToLog();
/**
* Pretty-print the json for all expectations that match the request to the log. They are printed into a dedicated log called mockserver_request.log
*
* @param httpRequest the http request that is matched against when deciding what to log if null all requests are logged
*/
public MockServerClient dumpToLog(HttpRequest httpRequest);
/**
* Reset MockServer by clearing all expectations
*/
public MockServerClient reset();
/**
* Stop MockServer gracefully (only support for Netty and Vert.X versions, not supported for WAR version)
*/
public MockServerClient stop();
/**
* Clear all expectations that match the http
*
* @param httpRequest the http request that is matched against when deciding whether to clear each expectation if null all expectations are cleared
*/
public MockServerClient clear(HttpRequest httpRequest);
/**
* Verify a request has been sent for example:
*
* mockServerClient
* .verify(
* request()
* .withPath("/some_path")
* .withBody("some_request_body")
* );
*
* @param httpRequests the http requests that must be matched for this verification to pass
* @throws AssertionError if the request has not been found
*/
public MockServerClient verify(HttpRequest... httpRequests); throws AssertionError
/**
* Verify a request has been sent for example:
*
* mockServerClient
* .verify(
* request()
* .withPath("/some_path")
* .withBody("some_request_body"),
* VerificationTimes.exactly(3)
* );
*
* Times supports multiple static factory methods:
*
* once() - verify the request was only received once
* exactly(n) - verify the request was only received exactly n times
* atLeast(n) - verify the request was only received at least n times
*
* @param httpRequest the http request that must be matched for this verification to pass
* @param times the number of times this request must be matched
* @throws AssertionError if the request has not been found
*/
public MockServerClient verify(HttpRequest httpRequest, org.mockserver.verify.VerificationTimes times); throws AssertionError
/**
* Retrieve the recorded requests that match the httpRequest parameter as expectations, use null for the parameter to retrieve all requests
*
* @param httpRequest the http request that is matched against when deciding whether to return each expectation, use null to retrieve for all requests
* @return an array of all expectations that have been recorded by the proxy
*/
public Expectation[] retrieveAsExpectations(HttpRequest httpRequest);
/**
* Retrieve the recorded requests that match the httpRequest parameter as a JSON array, use null for the parameter to retrieve all requests
*
* @param httpRequest the http request that is matched against when deciding whether to return each expectation, use null to retrieve for all requests
* @return a JSON array of all expectations that have been recorded by the proxy
*/
public String retrieveAsJSON(HttpRequest httpRequest);
}
Java Proxy Client
To simplest way to interact with proxy from Java is to use org.mockserver.client.proxy.ProxyClient which provides the following API:
public class ProxyClient {
/**
* Start the client communicating to the proxy at the specified host and port
* for example:
* ProxyClient mockServerClient = new ProxyClient("localhost", 1080);
*
* @param host the host for the proxy to communicate with
* @param port the port for the proxy to communicate with
*/
public ProxyClient(String host, int port);
/**
* Pretty-print the json for all requests / responses as Expectations to the log.
* They are printed into a dedicated log called mockserver_request.log
*/
public ProxyClient dumpToLogAsJSON();
/**
* Pretty-print the json for matching requests and their responses as Expectations to the log.
* They are printed into a dedicated log called mockserver_request.log
*
* @param httpRequest the http request that is matched against when deciding what to log if null all requests are logged
*/
public ProxyClient dumpToLogAsJSON(HttpRequest httpRequest);
/**
* Output Java code for creating all requests / responses as Expectations to the log.
* They are printed into a dedicated log called mockserver_request.log
*/
public ProxyClient dumpToLogAsJava();
/**
* Output Java code for creating matching requests and their responses as Expectations to the log.
* They are printed into a dedicated log called mockserver_request.log
*
* @param httpRequest the http request that is matched against when deciding what to log if null all requests are logged
*/
public ProxyClient dumpToLogAsJava(HttpRequest httpRequest);
/**
* Reset the proxy by clearing recorded requests
*/
public ProxyClient reset();
/**
* Stop the proxy gracefully (only support for Netty and Vert.X versions, not supported for WAR version)
*/
public ProxyClient stop();
/**
* Clear all recorded requests that match the httpRequest parameter
*
* @param httpRequest the http request that is matched against when deciding whether to clear recorded requests
*/
public ProxyClient clear(HttpRequest httpRequest);
/**
* Verify a request has been sent for example:
*
* mockServerClient
* .verify(
* request()
* .withPath("/some_path")
* .withBody("some_request_body")
* );
*
* @param httpRequest the http request that must be matched for this verification to pass
* @throws AssertionError if the request has not been found
*/
public ProxyClient verify(HttpRequest httpRequest); throws AssertionError
/**
* Verify a request has been sent for example:
*
* mockServerClient
* .verify(
* request()
* .withPath("/some_path")
* .withBody("some_request_body"),
* VerificationTimes.exactly(3)
* );
*
* Times supports multiple static factory methods:
*
* once() - verify the request was only received once
* exactly(n) - verify the request was only received exactly n times
* atLeast(n) - verify the request was only received at least n times
*
* @param httpRequest the http request that must be matched for this verification to pass
* @param times the number of times this request must be matched
* @throws AssertionError if the request has not been found
*/
public ProxyClient verify(HttpRequest httpRequest, Times times); throws AssertionError
/**
* Retrieve the recorded requests that match the httpRequest parameter as expectations, use null for the parameter to retrieve all requests
*
* @param httpRequest the http request that is matched against when deciding whether to return each expectation, use null for the parameter to retrieve for all requests
* @return an array of all expectations that have been recorded by the proxy
*/
public Expectation[] retrieveAsExpectations(HttpRequest httpRequest);
/**
* Retrieve the recorded requests that match the httpRequest parameter as a JSON array, use null for the parameter to retrieve all requests
*
* @param httpRequest the http request that is matched against when deciding whether to return each expectation, use null for the parameter to retrieve for all requests
* @return a JSON array of all expectations that have been recorded by the proxy
*/
public String retrieveAsJSON(HttpRequest httpRequest);
}
JavaScript MockServer Client
To interact with MockServer from JavaScript it is possible to use either:
- a browser based API file mockServerClient.js
- a Node.js npm module mockserver-client
To include the browser based in an HTML page use one of the following script tag to load the file from MaxCDN:
<script type="text/javascript" src="https://cdn.rawgit.com/jamesdbloom/mockserver/cd04edaf0ad132e3639af355d2ab4887f85e98ae/mockserver-client-javascript/src/main/javascript/mockServerClient.js"></script>
To use the Node.js module add the following code to your node project:
var mockServer = require('mockserver-client'),
mockServerClient = mockServer.mockServerClient;
Both versions of mockServerClient provide the same API as follows:
var mockServerClient = function (mockServerUrl) {
"use strict";
/**
* The default headers added to to the mocked response when using mockSimpleResponse(...)
*/
var defaultResponseHeaders = [
{'name': 'Content-Type', 'values': ['application/json; charset=utf-8']},
{'name': 'Cache-Control', 'values': ['no-cache, no-store']}
],
/**
* Setup an expectation in MockServer by specifying an expectation object
* for example:
*
* mockServerClient('localhost', 1080).mockAnyResponse(
* {
* 'httpRequest': {
* 'path': '/somePath',
* 'body': {
* 'type': 'STRING',
* 'value': 'someBody'
* }
* },
* 'httpResponse': {
* 'statusCode': 200,
* 'body': Base64.encode(JSON.stringify({ name: 'first_body' })),
* 'delay': {
* 'timeUnit': 'MILLISECONDS',
* 'value': 250
* }
* },
* 'times': {
* 'remainingTimes': 1,
* 'unlimited': false
* }
* }
* );
*
* @param expectation the expectation to setup in MockServer
*/
mockAnyResponse = function (expectation),
/**
* Setup an expectation in MockServer without having to specify the full expectation object
* for example:
*
* mockServerClient('localhost', 1080).mockSimpleResponse('/somePath', { 'name': 'value' }, 203);
*
* @param path the path to match requests against
* @param responseBody the response body to return if a request matches
* @param statusCode the response code to return if a request matches
*/
mockSimpleResponse = function (path, responseBody, statusCode),
/**
* Override the default headers that are used to specify the response headers in mockSimpleResponse(...)
* (note: if you use mockAnyResponse(...) the default headers are not used)
* for example:
*
* mockServerClient('localhost', 1080).setDefaultHeaders([
* {'name': 'Content-Type', 'values': ['application/json; charset=utf-8']},
* {'name': 'Cache-Control', 'values': ['no-cache, no-store']}
* ])
*
* @param headers the path to match requests against
*/
setDefaultHeaders = function (headers),
/**
* Verify a request has been sent for example:
*
* client.verify({
* 'httpRequest': {
* 'method': 'POST',
* 'path': '/somePath'
* }
* }, 2, true);
*
* @param request the http request that must be matched for this verification to pass
* @param count the number of times this request must be matched
* @param exact true if the count is matched as "equal to" or false if the count is matched as "greater than or equal to"
* @throws an error is the verify fails detailing which requests have been sent
*/
verify = function (request, count, exact),
/**
* Verify a sequence of requests has been sent for example:
*
* client.verifySequence(
* {
* 'method': 'POST',
* 'path': '/first_request'
* },
* {
* 'method': 'POST',
* 'path': '/second_request'
* },
* {
* 'method': 'POST',
* 'path': '/third_request'
* }
* );
*
* @param arguments the list of http requests that must be matched for this verification to pass
* @throws an error is the verify fails detailing which requests have been sent
*/
verifySequence = function (),
/**
* Reset MockServer by clearing all expectations
*/
reset = function (path),
/**
* Clear all expectations that match the specified path
*
* @param path the path to decide which expectations to cleared
*/
clear = function (path),
/**
* Pretty-print the json for all expectations for the specified path.
* This is particularly helpful when debugging expectations. The expectation
* are printed into a dedicated log called mockserver_request.log
*
* @param path the path to decide which expectations to dump to the log
*/
dumpToLogs = function (path);
return {
mockAnyResponse: mockAnyResponse,
mockSimpleResponse: mockSimpleResponse,
setDefaultHeaders: setDefaultHeaders,
verify: verify,
reset: reset,
clear: clear,
dumpToLogs: dumpToLogs
};
};
JavaScript Proxy Client
To interact with the proxy from JavaScript it is possible to use either:
- a browser based API file proxyClient.js
- a Node.js npm module mockserver-client
To include this file is an HTML page use one of the following script tag to load the file from MaxCDN:
<script type="text/javascript" src="https://cdn.rawgit.com/jamesdbloom/mockserver/cd04edaf0ad132e3639af355d2ab4887f85e98ae/mockserver-client-javascript/src/main/javascript/proxyClient.js"></script>
To use the Node.js module add the following code to your node project:
var mockServer = require('mockserver-client'),
proxyClient = mockServer.proxyClient;
Both versions of proxyClient provide the same API as follows:
var proxyClient = function (host, port) {
"use strict";
/**
* Retrieve the recorded requests that match the httpRequest parameter as a JSON array, use null for the parameter to retrieve all requests
*
* @param request the http request that is matched against when deciding whether to return each expectation, use null for the parameter to retrieve for all requests
* @param a JSON array of all expectations that have been recorded by the proxy
*/
var retrieve = function (request),
/**
* Verify a request has been sent for example:
*
* client.verify({
* 'httpRequest': {
* 'method': 'POST',
* 'path': '/somePath'
* }
* }, 2, true);
*
* @param request the http request that must be matched for this verification to pass
* @param count the number of times this request must be matched
* @param exact true if the count is matched as "equal to" or false if the count is matched as "greater than or equal to"
* @throws an error is the verify fails detailing which requests have been sent
*/
verify = function (request, count, exact),
/**
* Verify a sequence of requests has been sent for example:
*
* client.verifySequence(
* {
* 'method': 'POST',
* 'path': '/first_request'
* },
* {
* 'method': 'POST',
* 'path': '/second_request'
* },
* {
* 'method': 'POST',
* 'path': '/third_request'
* }
* );
*
* @param arguments the list of http requests that must be matched for this verification to pass
* @throws an error is the verify fails detailing which requests have been sent
*/
verifySequence = function (),
/**
* Reset the proxy by clearing all recorded requests
*/
reset = function (),
/**
* Clear all recorded requests that match the specified path
*
* @param path the path to decide which expectations to cleared
*/
clear = function (path),
/**
* Pretty-print the json for all requests / responses that match the specified path
* as Expectations to the log. They are printed into a dedicated log called mockserver_request.log
*
* @param path the path to decide which expectations to dump to the log
*/
dumpToLogs = function (path);
return {
retrieve: retrieve,
verify: verify,
reset: reset,
clear: clear,
dumpToLogs: dumpToLogs
};
};
Starting MockServer
Before any mock expectation can be sent to MockServer it must be started.
The mock server can be run:
- via a Maven Plugin as part of a Maven build cycle
- programmatically via an API in an @Before or @After method
- using a JUnit @Rule via a @Rule annotated field in a JUnit test
- from the command line as a stand-alone process in a test environment
- as a Docker container in any Docker enabled environment
- as a Vert.X module as part of an existing Vert.X environment
- as a deployable WAR to an existing application server
- as a Grunt plugin as part of a Grunt build cycle
- as a Node.js (npm) module from any Node.js code
MockServer is available as:
- a stand alone Netty web server that is fully self contained
- a deployable WAR that runs on any JEE web server
- a fully encapsulated Docker container
- a Vert.X module that runs on a Vert.X
It is also possible to build and run MockServer directly from source code as described below
Maven Plugin
To run MockServer as part of your build add the following plugin to your pom.xml:
<plugin>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-maven-plugin</artifactId>
<version>3.9.9</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>
This will start MockServer during the process-test-classes phase and will stop MockServer during the verify phase. For more details about Maven build phases see: Introduction to the Build Lifecycle.
This ensures that any integration tests you run during the test or integration-test phases can use MockServer on the port specified.
It is also possible to run MockServer as a forked JVM using the runForked and stopForked goals as follows:
<plugin>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-maven-plugin</artifactId>
<version>3.9.9</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>runForked</goal>
</goals>
</execution>
<execution>
<id>verify</id>
<phase>verify</phase>
<goals>
<goal>stopForked</goal>
</goals>
</execution>
</executions>
</plugin>
Note: If you use the runForked goal as above and the test phase fails (because a test has failed) MockServer will not be stopped as Maven does not run any more phases after a phase has failed. In the case above the verify phase is not run if a test fails so the forked MockServer will not be stopped. If you want to ensure MockServer is stopped even when there are test failures make sure you use start and stop goals as these run MockServer on a separate thread that is stopped however maven exits (even if a test fails).
These goals can be used from the command line as well to start and stop MockServer, as follows:
To run MockServer synchronously and block:
mvn mockserver:run
To run MockServer asynchronously as a forked JVM:
mvn mockserver:runForked
To stop a forked instance of MockServer running on the same machine:
mvn mockserver:stopForked
The stopForked goal does assumes that MockServer is running on the same physical machine as it uses <IP_ADDRESS> to communicate with MockServer stop socket.
The Maven plugin has the following goals:
- start - start MockServer, do not block, but stop when build ends
- stop - stop a MockServer started earlier as part of the current build
- run - run MockServer and block waiting for requests (timeout config if provided limits how long to block for)
- runForked - run MockServer as separate forked JVM, do not block, stay alive when build ends
- stopForked - stop a forked MockServer, previously started by a runForked goal
The Maven plugin can be configured as follows:
- serverPort - The port MockServer listens to incoming HTTP and HTTPS requests, port unification is used to support HTTP and HTTPS on the same port (required: false - but at least one of the two ports must be specified)
- proxyPort - The port the proxy listens to incoming HTTP, HTTP -> HTTPS CONNECT, HTTPS and SOCKS requests, port unification supports for all protocols on the same port (required: false - but at least one of the two ports must be specified)
- timeout - How long to block waiting for MockServer, used by run goal, 0 means wait indefinitely (required: false, default: 0)
- logLevel - The logging level (required: false, default: WARN)
- skip - Prevent the plugin from running (required: false, default: false)
- initializationClass - To enable the creation of default expectations that are generic across all tests or mocking scenarios a class can be specified to initialize expectations in MockServer, this class must implement org.mockserver.initialize.ExpectationInitializer interface, the initializeExpectations(MockServerClient mockServerClient) method will be called once MockServer has been started (but ONLY if serverPort has been set), however it should be noted that it is generally better practice to create all expectations locally in each test (or test class) for clarity, simplicity and to avoid brittle tests. Note: that the plugin must be started during the process-test-classes to ensure that the initialization class has been compiled from either src/main/java or src/test/java locations. (required: false, default: false)
Client API - starting and stopping
Use the client API to run MockServer programmatically.
First add the following maven dependency:
<!-- mockserver -->
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-netty</artifactId>
<version>3.9.9</version>
</dependency>
To start the server and create a client the simplest way is to the start factory methods ClientAndServer.startClientAndServer or ClientAndProxy.startClientAndProxy as follows:
Add includes:
import static org.mockserver.integration.ClientAndProxy.startClientAndProxy;
import static org.mockserver.integration.ClientAndServer.startClientAndServer;
Add fields:
private ClientAndProxy proxy;
private ClientAndServer mockServer;
Use factory method to start server and client when appropriate, for example in @Before method:
@Before
public void startProxy() {
mockServer = startClientAndServer(8080);
proxy = startClientAndProxy(9090);
}
Stop server and client when appropriate, for example in @After method:
@After
public void stopProxy() {
proxy.stop();
mockServer.stop();
}
The mockserver-example project contains an example test called BookPageIntegrationTest that demonstrates a fully working example.
Running MockServer via a JUnit @Rule
MockServer can be run using the MockServerRule. The MockServerRule starts MockServer on a free port before the any test runs and stops MockServer after all tests have completed. A MockServerClient is then assigned to any field in the unit test of type org.mockserver.client.server.MockServerClient
@Rule
public MockServerRule mockServerRule = new MockServerRule(this);
private MockServerClient mockServerClient;
Any test method can now use the mockServerClient field to create expectation or verify requests.
The MockServerRule has the following constructors:
/**
* Start MockServer prior to test execution and stop MockServer after the tests have completed.
* This constructor dynamically allocates a free port for MockServer to use.
*
* @param target an instance of the test being executed
*/
public MockServerRule(Object target);
/**
* Start MockServer prior to test execution and stop MockServer after the tests have completed.
* This constructor dynamically allocates a free port for MockServer to use.
*
* @param target an instance of the test being executed
* @param perTestSuite indicates how many instances of MockServer are created
* if true a single MockServer is created per JVM
* if false one instance per test class is created
*/
public MockServerRule(Object target, boolean per TestSuite);
/**
* Start the proxy prior to test execution and stop the proxy after the tests have completed.
* This constructor dynamically create a proxy that accepts HTTP requests on the specified port
*
* @param httpPort the HTTP port for the proxy
* @param target an instance of the test being executed
*/
public MockServerRule(Integer httpPort, Object target);
/**
* Start the proxy prior to test execution and stop the proxy after the tests have completed.
* This constructor dynamically create a proxy that accepts HTTP requests on the specified port
*
* @param httpPort the HTTP port for the proxy
* @param target an instance of the test being executed
* @param perTestSuite indicates how many instances of MockServer are created
* if true a single MockServer is created per JVM
* if false one instance per test class is created
*/
public MockServerRule(Integer httpPort, Object target, boolean per TestSuite);
/**
* Start the proxy prior to test execution and stop the proxy after the tests have completed.
* This constructor dynamically create a proxy that accepts HTTP and HTTPS requests on the specified ports
*
* @param httpPort the HTTP port for the proxy
* @param httpsPort the HTTPS port for the proxy
* @param target an instance of the test being executed
* @param perTestSuite indicates how many instances of MockServer are created
* if true a single MockServer is created per JVM
* if false one instance per test class is created
*/
public MockServerRule(Integer httpPort, Integer httpsPort, Object target, boolean per TestSuite);
The proxy can be run using the ProxyRule. The ProxyRule starts the proxy before the any test runs and stops the proxy after all tests have completed. A ProxyClient is then assigned to any field in the unit test of type org.mockserver.client.proxy.ProxyClient
@Rule
public ProxyRule proxyRule = new ProxyRule(8080, this);
private ProxyClient proxyClient;
Any test method can now use the proxyClient field to verify requests or anaylse a system's behaviour.
The ProxyRule has the following constructors:
/**
* Start the proxy prior to test execution and stop the proxy after the tests have completed.
* This constructor dynamically allocates a free port for the proxy to use.
* Note: The getHttpPort getter can be used to retrieve the dynamically allocated port.
*
* @param target an instance of the test being executed
*/
public ProxyRule(Object target);
/**
* Start the proxy prior to test execution and stop the proxy after the tests have completed.
* This constructor dynamically allocates a free port for the proxy to use.
*
* @param target an instance of the test being executed
* @param perTestSuite indicates how many instances of the proxy are created
* if true a single proxy is created per JVM
* if false one instance per test class is created
*/
public ProxyRule(Object target, boolean per TestSuite);
/**
* Start the proxy prior to test execution and stop the proxy after the tests have completed.
* This constructor dynamically create a proxy that accepts HTTP requests on the specified port
*
* @param httpPort the HTTP port for the proxy
* @param target an instance of the test being executed
*/
public ProxyRule(Integer httpPort, Object target);
/**
* Start the proxy prior to test execution and stop the proxy after the tests have completed.
* This constructor dynamically create a proxy that accepts HTTP requests on the specified port
*
* @param httpPort the HTTP port for the proxy
* @param target an instance of the test being executed
* @param perTestSuite indicates how many instances of the proxy are created
* if true a single proxy is created per JVM
* if false one instance per test class is created
*/
public ProxyRule(Integer httpPort, Object target, boolean per TestSuite);
/**
* Start the proxy prior to test execution and stop the proxy after the tests have completed.
* This constructor dynamically create a proxy that accepts HTTP and HTTPS requests on the specified ports
*
* @param httpPort the HTTP port for the proxy
* @param httpsPort the HTTPS port for the proxy
* @param target an instance of the test being executed
* @param perTestSuite indicates how many instances of the proxy are created
* if true a single proxy is created per JVM
* if false one instance per test class is created
*/
public ProxyRule(Integer httpPort, Integer httpsPort, Object target, boolean per TestSuite);
Running From Command Line
MockServer can be run directly from the command line and using Netty as follow:
download mockserver-netty-3.9.9-jar-with-dependencies.jar from Maven Central
-
java -jar <path to mockserver-netty-3.9.9-jar-with-dependencies.jar> -serverPort <port>
The command line supports the following options:
java -jar <path to jar> [-serverPort <port>] \
[-proxyPort <port>]
valid options are:
-serverPort <port> specifies the HTTP and HTTPS port for the
MockServer port unification is used to
support HTTP and HTTPS on the same port
-proxyPort <path> specifies the HTTP, HTTPS, SOCKS and HTTP
CONNECT port for proxy, port unification
supports for all protocols on the same port
For example:
java -Dmockserver.logLevel=DEBUG -jar ~/Downloads/mockserver-netty-3.9.9-jar-with-dependencies.jar -serverPort 8080 -proxyPort 9090
Docker Container
MockServer can be run as a Docker container.
First, you'll need to install Docker.
Then to run MockServer as a Docker container run the following command:
docker run -d -P jamesdbloom/mockserver
This command will map the ports exposed by MockServer and Proxy to dynamic ports using the -P option. To specify which ports are used you can specify one or more port mappings using the -p <host port>:<container port> option. You only need to specify mapping for ports you need to use, for example, if you are not using the proxy there is no need to provide port mapping options for the proxy ports.
To run MockServer specifying as a Docker container run the following command (replacing each < ... > section with the appropriate port value):
docker run -d -p <serverPort>:8080 -p <proxyPort>:9090 jamesdbloom/mockserver
Note: you only need to specify mapping for ports you need to use, for example, if you are only using MockServer to mock HTTP endpoints then only specify -p <serverPort>:8080 as follows (replacing each < ... > section with the appropriate port value):
docker run -d -p <serverPort>:8080 jamesdbloom/mockserver
This MockServer docker container exposes the following ports:
- serverPort 8080
- proxyPort 9090
Vert.X Module
MockServer can be run as a Vert.X module. However, support for the Vert.X module was stopped at version 2.9. This is because Vert.X requires Java 7 and MockServer Vert.X module was the only MockServer module that relied on Java 7 making the build and development process more complex.
First, you'll need to install Vert.x.
Then to run MockServer as Vert.X module run the following command:
vertx install org.mock-server~mockserver-vertx~2.9
export VERTX_OPTS="-Dmockserver.serverPort=8080 -Dmockserver.serverSecurePort=1443 -Dmockserver.logLevel=TRACE"
vertx runmod org.mock-server~mockserver-vertx~2.9
The specify the HTTP port and / or HTTPS port the VERTX_OPTS environment variable must be set specifying the system property mockserver.serverPort for the HTTP port and mockserver.serverSecurePort for the HTTPS port.
Note: At least one of either the HTTP or the HTTPS port must be specified for MockServer to run.
export VERTX_OPTS="-Dmockserver.serverPort=8080 -Dmockserver.serverSecurePort=1443 -Dmockserver.logLevel=TRACE"
It is also possible to update the default logging level by setting the system properties mockserver.logLevel as above.
Web Archive (WAR)
To run as a WAR deployed on any JEE web server:
- download mockserver-war-3.9.9.war from Maven Central
- deploy mockserver-war-3.9.9.war to any JEE web server
WAR Context Path
The WAR context path is ignored from all request matching for path.
The MockServerClient constructor includes an argument for the context path that the WAR has been deployed to, as follows:
public MockServerClient(String host, int port, String contextPath)
Build & Run From Source
MockServer is now only built using maven as the use of gradle caused problems with the Travis CI environment so the gradle build was removed.
First clone the repository as follows:
git clone https://github.com/jamesdbloom/mockservice.git
cd mockserver
Next build and run the project using maven.
Maven
To build an executable jar containing all dependencies run the following command:
mvn clean package
This will produce a jar file under the target directory called, as follows:
mockserver-netty/target/mockserver-netty-3.9.9-jar-with-dependencies.jar
Run MockServer then using the executable jar as per the instruction above in Running From The Command Line
Create Client For Existing MockServer or Proxy
To create a pointing at an existing endpoint using the MockServerClient and ProxyClient constructors, for example:
@Before
public void startProxy() {
mockServer = new MockServerClient("localhost", 8080);
proxy = new ProxyClient("localhost", 9090);
}
The MockServerClient has the following methods:
/**
* Start the client communicating to a MockServer at the specified host and port
* for example:
*
* MockServerClient mockServerClient = new MockServerClient("localhost", 8080);
*
* @param host the host for MockServer to communicate with
* @param port the port for MockServer to communicate with
*/
public MockServerClient(String host, int port);
/**
* Start the client communicating to a MockServer at the specified host and port
* and contextPath for example:
*
* MockServerClient mockServerClient = new MockServerClient("localhost", 8080, "/mockserver");
*
* @param host the host for MockServer to communicate with
* @param port the port for MockServer to communicate with
* @param contextPath the context path that MockServer war is deployed to
*/
public MockServerClient(String host, int port, String contextPath);
/**
* Specify an unlimited expectation that will respond regardless of the number of matching http
* for example:
*
* mockServerClient
* .when(
* request()
* .withPath("/some_path")
* .withBody("some_request_body")
* )
* .respond(
* response()
* .withBody("some_response_body")
* .withHeaders(
* new Header("responseName", "responseValue")
* )
* );
*
* or:
* mockServerClient
* .when(
* request()
* .withPath("/some_path")
* .withBody("some_request_body")
* )
* .forward(
* forward()
* .withHost("some_host_name")
* .withPort(80)
* );
*
* @param httpRequest the http request that must be matched for this expectation to respond
* @return an Expectation object that can be used to specify the response
*/
public ForwardChainExpectation when(HttpRequest httpRequest);
/**
* Specify an limited expectation that will respond a specified number of times when the http is matched
* for example:
*
* mockServerClient
* .when(
* new HttpRequest()
* .withPath("/some_path")
* .withBody("some_request_body"),
* Times.exactly(5)
* )
* .respond(
* new HttpResponse()
* .withBody("some_response_body")
* .withHeaders(
* new Header("responseName", "responseValue")
* )
* );
*
* or:
* mockServerClient
* .when(
* request()
* .withPath("/some_path")
* .withBody("some_request_body"),
* Times.once()
* )
* .forward(
* forward()
* .withHost("some_host_name")
* .withPort(80)
* );
*
* @param httpRequest the http request that must be matched for this expectation to respond
* @param times the number of times to respond when this http is matched
* @return an Expectation object that can be used to specify the response
*/
public ForwardChainExpectation when(HttpRequest httpRequest, Times times);
/**
* Pretty-print the json for all expectations to the log.
* They are printed into a dedicated log called mockserver_request.log
*/
public MockServerClient dumpToLog();
/**
* Pretty-print the json for all expectations that match the request to the log.
* They are printed into a dedicated log called mockserver_request.log
*
* @param httpRequest the http request that is matched against when deciding what to log
* if null all requests are logged
*/
public MockServerClient dumpToLog(HttpRequest httpRequest);
/**
* Reset MockServer by clearing all expectations
*/
public MockServerClient reset();
/**
* Clear all expectations that match the http
*
* @param httpRequest the http request that is matched against when deciding whether to clear each expectation
* if null all expectations are cleared
*/
public MockServerClient clear(HttpRequest httpRequest);
The ProxyClient has the following methods:
/**
* Start the client communicating to the proxy at the specified host and port
* for example:
* ProxyClient mockServerClient = new ProxyClient("localhost", 1080);
*
* @param host the host for the proxy to communicate with
* @param port the port for the proxy to communicate with
*/
public ProxyClient(String host, int port);
/**
* Pretty-print the json for all requests / responses as Expectations to the log.
* They are printed into a dedicated log called mockserver_request.log
*/
public ProxyClient dumpToLogAsJSON();
/**
* Pretty-print the json for matching requests and their responses as Expectations to the log.
* They are printed into a dedicated log called mockserver_request.log
*
* @param httpRequest the http request that is matched against when deciding what to log
* if null all requests are logged
*/
public ProxyClient dumpToLogAsJSON(HttpRequest httpRequest);
/**
* Output Java code for creating all requests / responses as Expectations to the log.
* They are printed into a dedicated log called mockserver_request.log
*/
public ProxyClient dumpToLogAsJava();
/**
* Output Java code for creating matching requests and their responses as Expectations to the log.
* They are printed into a dedicated log called mockserver_request.log
*
* @param httpRequest the http request that is matched against when deciding what to log
* if null all requests are logged
*/
public ProxyClient dumpToLogAsJava(HttpRequest httpRequest);
/**
* Reset the proxy by clearing recorded requests
*/
public ProxyClient reset();
/**
* Clear all recorded requests that match the httpRequest parameter
*
* @param httpRequest the http request that is matched against when deciding whether to clear recorded requests
*/
public ProxyClient clear(HttpRequest httpRequest);
/**
* Verify a request has been sent for example:
*
* mockServerClient
* .verify(
* request()
* .withPath("/some_path")
* .withBody("some_request_body")
* );
*
* @param httpRequest the http request that must be matched for this verification to pass
* @throws AssertionError if the request has not been found
*/
public ProxyClient verify(HttpRequest httpRequest) throws AssertionError;
/**
* Verify a request has been sent for example:
*
* mockServerClient
* .verify(
* request()
* .withPath("/some_path")
* .withBody("some_request_body"),
* VerificationTimes.exactly(3)
* );
*
* @param httpRequest the http request that must be matched for this verification to pass
* @param times the number of times this request must be matched
* @throws AssertionError if the request has not been found
*/
public ProxyClient verify(HttpRequest httpRequest, Times times) throws AssertionError;
/**
* Retrieve the recorded requests that match the httpRequest parameter as expectations
*
* @param httpRequest the http request that is matched against when deciding whether to return each expectation,
* use null for the parameter to retrieve for all requests
* @return an array of all expectations that have been recorded by the proxy
*/
public Expectation[] retrieveAsExpectations(HttpRequest httpRequest);
/**
* Retrieve the recorded requests that match the httpRequest parameter as a JSON array
*
* @param httpRequest the http request that is matched against when deciding whether to return each expectation,
* use null for the parameter to retrieve for all requests
* @return a JSON array of all expectations that have been recorded by the proxy
*/
public String retrieveAsJSON(HttpRequest httpRequest);
Create Expectations
To create an expectation you need to define:
- the request matcher and
- what response should be returned or
- what callback should be executed or
- where the request should be forwarded.
MockServer will play expectations in the exact order they are setup. For example, if an expectation A is setup to response (or forward) 3 times then expectation B is setup to response (or forward) 2 times for the same request MockServer will response (or forward) in the following order A, A, A, B, B.
Java
To setup an expectation that responds to a request:
new MockServerClient("<IP_ADDRESS>", 8080)
.when(
request()
.withMethod("POST")
.withPath("/login")
.withQueryStringParameters(
new Parameter("returnUrl", "/account")
)
.withCookies(
new Cookie("sessionId", "2By8LOhBmaW5nZXJwcmludCIlMDAzMW")
)
.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(new Delay(SECONDS, 1))
);
To setup an expectation that forwards to a request:
new MockServerClient("<IP_ADDRESS>", 8080)
.when(
request()
.withMethod("GET")
.withPath("/index.html"),
exactly(1)
)
.forward(
forward()
.withHost("www.mock-server.com")
.withPort(80)
.withScheme(HTTP)
);
Note: this requires the use of these static imports as follows:
import static org.mockserver.model.HttpRequest.request;
import static org.mockserver.model.HttpResponse.response;
import static org.mockserver.model.HttpForward.forward;
import static org.mockserver.matchers.Times.exactly;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.mockserver.model.HttpForward.Scheme.HTTP;
The mockserver-example project contains an example test called BookPageIntegrationTest that demonstrates a fully working example.
JavaScript
To setup an expectation that responds to a request:
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("PUT", "http://localhost:8080/expectation", false);
xmlHttpRequest.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xmlHttpRequest.send(JSON.stringify({
"httpRequest": {
"method": "POST",
"path": "/login",
"queryStringParameters": [
{
"name": "returnUrl",
"values": ["/account"]
}
],
"cookies": [
{
"name": "sessionId",
"values": ["2By8LOhBmaW5nZXJwcmludCIlMDAzMW"]
}
],
"body": {
"type": "JSON",
"value": JSON.stringify({ username: "foo", password: "bar" })
}
},
"httpResponse": {
"statusCode": 401,
"headers": [
{
"name": "Content-Type",
"values": ["application/json; charset=utf-8"]
},
{
"name": "Cache-Control",
"values": ["public, max-age=86400"]
}
],
"body": JSON.stringify({ message: "incorrect username and password combination" }),
"delay": {
"timeUnit": "SECONDS",
"value": 1
}
},
"times": {
"remainingTimes": 1,
"unlimited": false
}
}));
To setup an expectation that forwards to a request:
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("PUT", "http://localhost:8080/expectation", false);
xmlHttpRequest.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xmlHttpRequest.send(JSON.stringify({
"httpRequest": {
"method": "GET",
"path": "/index.html"
},
"httpForward": {
"host": "www.mock-server.com",
"port": 80,
"scheme": "HTTP"
},
"times": {
"remainingTimes": 1,
"unlimited": false
}
}));
Request Matcher
To specify when a response should be mocked a request matcher must be provided in each expectation.
When an incoming request matches the request matcher in an expectation MockServer will return the response for that expectation.
Requests can be matched on:
- path - regex or plain text
- query string - regex or plain text
- headers - regex or plain text
- cookies - regex or plain text
- body - XPath, json, regex, plain text (exact match), or body parameters
The body can be matched using plain text, a json expression, an XPath expression or a regular expression, see XPath Expression Syntax for supported XPath syntax.
A json expressions is a valid json object. When a json expression is matched against a request body only fields in the json expression are matched, any extra fields in the request body not specified in the json expression will be ignored, in addition the order of fields in the body will be ignored.
All other matching can be done using plain text or a regular expression, see Pattern (Java Platform SE 6) for supported regular expression syntax.
Java
To specify a request matcher in Java use the org.mockserver.model.HttpRequest class which specifies the details of each HTTP response with a fluent API:
public class HttpRequest {
/**
* The HTTP method to match on such as "GET" or "POST"
*
* @param method the HTTP method such as "GET" or "POST"
*/
public HttpRequest withMethod(String method);
/**
* The path to match on such as "/some_mocked_path" any servlet context path is ignored for matching and should not be specified here
* regex values are also supported such as ".*_path", see http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html
* for full details of the supported regex syntax
*
* @param path the path such as "/some_mocked_path" or a regex
*/
public HttpRequest withPath(String path);
/**
* The query string parameters to match on as a list of Parameter objects where the values or keys of each parameter
* can be either a string or a regex (for more details of the supported regex syntax
* see http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html)
*
* @param parameters the list of Parameter objects where the values or keys of each parameter can be either a string or a regex
*/
public HttpRequest withQueryStringParameters(List<Parameter> parameters);
/**
* The query string parameters to match on as a varags Parameter objects where the values or keys of each parameter
* can be either a string or a regex (for more details of the supported regex syntax
* see http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html)
*
* @param parameters the varags Parameter objects where the values or keys of each parameter can be either a string or a regex
*/
public HttpRequest withQueryStringParameters(Parameter... parameters);
/**
* The query string parameters to match on as a Map<String, List<String>> where the values or keys of each parameter
* can be either a string or a regex (for more details of the supported regex syntax
* see http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html)
*
* @param parameters the Map<String, List<String>> object where the values or keys of each parameter can be either a string or a regex
*/
public HttpRequest withQueryStringParameters(Map<String, List<String>> parameters);
/**
* Adds one query string parameter to match on as a Parameter object where the parameter values list can be a list of strings
* or regular expressions (for more details of the supported regex syntax
* see http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html)
*
* @param parameter the Parameter object which can have a values list of strings or regular expressions
*/
public HttpRequest withQueryStringParameter(Parameter parameter);
/**
* The body to match on such as "this is an exact string body" or a json expression such as "{username: 'foo', password: 'bar'}" or a regex
* (see http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html)
* or an XPath expression which returns one or more values or evaluates to true
* (see http://saxon.sourceforge.net/saxon6.5.3/expressions.html)
*
* @param body the body on such as "this is an exact string body"
* or a regex such as "username[a-z]{4}"
* or a json expression such as "{username: 'foo', password: 'bar'}"
* or an XPath such as "/element[key = 'some_key' and value = 'some_value']"
*/
public HttpRequest withBody(String body);
/**
* The body match rules on such as using one of the Body subclasses as follows:
*
* exact string match:
* - exact("this is an exact string body"); or
* - new StringBody("this is an exact string body")
*
* exact match:
* - regex("username[a-z]{4}"); or
* - new StringBody("username[a-z]{4}", Body.Type.REGEX);
*
* json match:
* - json("{username: 'foo', password: 'bar'}"); or
* - new StringBody("{username: 'foo', password: 'bar'}", Body.Type.JSON);
*
* xpath match:
* - xpath("/element[key = 'some_key' and value = 'some_value']"); or
* - new StringBody("/element[key = 'some_key' and value = 'some_value']", Body.Type.XPATH);
*
* body parameter match:
* - params(
* param("name_one", "value_one_one", "value_one_two")
* param("name_two", "value_two")
* ); or
* - new ParameterBody(
* new Parameter("name_one", "value_one_one", "value_one_two")
* new Parameter("name_two", "value_two")
* );
*
* binary match:
* - binary(IOUtils.readFully(getClass().getClassLoader().getResourceAsStream("example.pdf"), 1024)); or
* - new BinaryBody(IOUtils.readFully(getClass().getClassLoader().getResourceAsStream("example.pdf"), 1024));
*
* for more details of the supported regex syntax see http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html
* for more details of the supported json syntax see http://jsonassert.skyscreamer.org
* for more detail of XPath syntax see http://saxon.sourceforge.net/saxon6.5.3/expressions.html
*
* @param body an instance of one of the Body subclasses including StringBody or ParameterBody
*/
public HttpRequest withBody(Body body);
/**
* The headers to match on as a list of Header objects where the values or keys of each header can be either a string or a regex
* (for more details of the supported regex syntax see http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html)
*
* @param headers the list of Header objects where the values or keys of each header can be either a string or a regex
*/
public HttpRequest withHeaders(List<Header> headers);
/**
* The headers to match on as a varags of Header objects where the values or keys of each header can be either a string or a regex
* (for more details of the supported regex syntax see http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html)
*
* @param headers the varags of Header objects where the values or keys of each header can be either a string or a regex
*/
public HttpRequest withHeaders(Header... headers);
/**
* Adds one header to match on as a Header object where the header values list can be a list of strings or regular expressions
* (for more details of the supported regex syntax see http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html)
*
* @param header the Header object which can have a values list of strings or regular expressions
*/
public HttpRequest withHeader(Header header);
/**
* The cookies to match on as a list of Cookie objects where the values or keys of each cookie can be either a string or a regex
* (for more details of the supported regex syntax see http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html)
*
* @param cookies the list of Cookie objects where the values or keys of each cookie can be either a string or a regex
*/
public HttpRequest withCookies(List<Cookie> cookies);
/**
* The cookies to match on as a varags Cookie objects where the values or keys of each cookie can be either a string or a regex
* (for more details of the supported regex syntax see http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html)
*
* @param cookies the varags Cookie objects where the values or keys of each cookie can be either a string or a regex
*/
public HttpRequest withCookies(Cookie... cookies);
/**
* Adds one cookie to match on as a Cookie object where the cookie values list can be a list of strings or regular expressions
* (for more details of the supported regex syntax see http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html)
*
* @param cookie the Cookie object which can have a values list of strings or regular expressions
*/
public HttpRequest withCookie(Cookie cookie);
}
For example:
HttpRequest httpRequest =
request()
.withMethod("POST")
.withPath("/login")
.withBody("{username: 'foo', password: 'bar'}")
.withQueryStringParameters(
new Parameter("returnUrl", "/account")
)
.withCookies(
new Cookie("sessionId", "2By8LOhBmaW5nZXJwcmludCIlMDAzMW")
);
JavaScript
To specify a request matcher in javascript use JSON to specify the details with the following format:
"httpRequest": {
"method": "",
"path": "",
"queryParameters": []
"body": {
"type": <"STRING" or "REGEX" or "JSON" or "XPATH" or "PARAMETERS">,
"value": "" ( or "parameters" as shown in more detail below )
},
"cookies": [],
"headers": [],
}
Note: Only values which are matched on need to be specified, if a value is missing then it will not be matched on. For example, below both the parameters and headers fields are not specified.
Each cookie, header or parameter array entry has the following syntax:
{
"name": "someName",
"values": ["someValueOne", "someValueTwo", ...]
}
The same example, as in Java above, in JavaScript would be :
"httpRequest": {
"method": "POST",
"path": "/login",
"queryStringParameters": [
{
"name": "returnUrl",
"values": ["/account"]
}
],
"cookies": [
{
"name": "sessionId",
"values": ["2By8LOhBmaW5nZXJwcmludCIlMDAzMW"]
}
],
"body": {
"type": "STRING",
"value": "{username: 'foo', password: 'bar'}"
}
}
The "type" value in "body" can be:
"STRING"
"REGEX"
"JSON"
"XPATH"
"PARAMETERS"
When the "type" field has a value of "STRING", "REGEX", "JSON" or "XPATH" the other field of "body"" should be "value" and it should provide a string to perform the match against, as shown in the example above.
When the "type" field has a value of "PARAMETERS" the other field of "body" should be "parameters" and it should provide a list of body parameters using the following syntax:
{
"name": "someName",
"values": ["someValueOne", "someValueTwo", ...]
}
For example:
"httpRequest": {
"method": "POST",
"path": "/login",
"queryStringParameters": [
{
"name": "returnUrl",
"values": ["/account"]
}
],
"cookies": [
{
"name": "sessionId",
"values": ["2By8LOhBmaW5nZXJwcmludCIlMDAzMW"]
}
],
"body": {
"type": "PARAMETERS",
"parameters": [
{
"name": "username",
"values": ["foo"]
},
{
"name": "password",
"values": ["bar"]
}
]
}
}
When the "type" field has a value of "STRING" a short hand can be used where the "body" is only specified as a string literal for example:
"httpRequest": {
"method": "POST",
"path": "/login",
"queryStringParameters": [
{
"name": "returnUrl",
"values": ["/account"]
}
],
"cookies": [
{
"name": "sessionId",
"values": ["2By8LOhBmaW5nZXJwcmludCIlMDAzMW"]
}
],
"body": "a string body showing the short-hand way to specify a simple string body"
}
Times
The org.mockserver.matchers.Times class is used to specify how many times you want MockServer to match a request:
To create an instance of Times use one of the static factory methods:
Times.unlimited();
Times.once();
Times.exactly(int count);
Mock Responses
Response actions contain:
- status code i.e. 200, 302, 404, etc
- body - a UTF-8 encoded sequence of bytes containing any content
- headers - each with a name and one or more values
- cookies - each with a name and with one or more values, more complex cookies can be modelled by using the a Set-Cookie header
Responses can be further controlled using:
- a delay before the response is sent
- the number of times the response is sent (including unlimited)
Java
To mock a response in Java use the org.mockserver.model.HttpResponse class which specifies the details of each HTTP response with a fluent API:
public class HttpResponse {
/**
* The status code to return, such as 200, 404, the status code specified
* here will result in the default status message for this status code for
* example for 200 the status message "OK" is used
*
* @param statusCode an integer such as 200 or 404
*/
public HttpResponse withStatusCode(Integer responseCode);
/**
* The cookies to return as Set-Cookie headers as a list of Cookie objects
*
* @param cookies a list of Cookie objects
*/
public HttpResponse withCookies(List<Cookie> cookies);
/**
* The cookies to return as Set-Cookie headers as a varargs of Cookie objects
*
* @param cookies a varargs of Cookie objects
*/
public HttpResponse withCookies(Cookie... cookies);
/**
* Add cookie to return as Set-Cookie header
*
* @param cookie a Cookie object
*/
public HttpResponse withCookie(Cookie cookie);
/**
* The headers to return as a list of Header objects
*
* @param headers a list of Header objects
*/
public HttpResponse withHeaders(List<Header> headers);
/**
* The headers to return as a varargs of Header objects
*
* @param headers a varargs of Header objects
*/
public HttpResponse withHeaders(Header... headers);
/**
* A header to return as a Header objects
*
* @param header a Header objects
*/
public HttpResponse withHeader(Header header)
/**
* Set response body to return as a simple UTF-8 string response body
*
* @param body a "UTF-8" string
*/
public HttpResponse withBody(String body);
/**
* * Set response body to return as binary such as a pdf or image
*
* @param body a byte array
*/
public HttpResponse withBody(byte[] body);
/**
* Set the body to return for example:
*
* string body:
* - exact("<html><head/><body><div>a simple string body</div></body></html>"); or
* - new StringBody("<html><head/><body><div>a simple string body</div></body></html>")
*
* binary body:
* - binary(IOUtils.readFully(getClass().getClassLoader().getResourceAsStream("example.pdf"), 1024)); or
* - new BinaryBody(IOUtils.readFully(getClass().getClassLoader().getResourceAsStream("example.pdf"), 1024));
*
* @param body an instance of one of the Body subclasses including StringBody or BinaryBody
*/
public HttpResponse withBody(Body body);
/**
* The delay before responding with this request as a Delay object, for example new Delay(TimeUnit.SECONDS, 3)
*
* @param delay a Delay object, for example new Delay(TimeUnit.SECONDS, 3)
*/
public HttpResponse withDelay(Delay delay);
}
For example:
HttpResponse httpResponse =
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(new Delay(TimeUnit.SECONDS, 1));
JavaScript
To mock a response in javascript use JSON to specify the details with the following format:
"httpResponse": {
"statusCode": 200,
"body": "",
"cookies": [],
"headers": [],
"delay": {
"timeUnit": "MICROSECONDS",
"value": 0
}
}
Each cookie or header array entry has the following syntax:
{
"name": "someName",
"values": ["someValueOne", "someValueTwo", ...]
}
The "timeUnit" value in "delay" can be:
"NANOSECONDS"
"MICROSECONDS"
"MILLISECONDS"
"SECONDS"
"MINUTES"
"HOURS"
"DAYS"
The same example as above would be:
"httpResponse": {
"statusCode": 401,
"headers": [
{
"name": "Content-Type",
"values": ["application/json; charset=utf-8"]
},
{
"name": "Cache-Control",
"values": ["public, max-age=86400"]
}
],
"body": JSON.stringify({ message: "incorrect username and password combination" }),
"delay": {
"timeUnit": "SECONDS",
"value": 1
}
}
Mock Forward
Forward actions contain:
- host - the host to forward to i.e. www.mock-server.com
- port - the port to forward to, this defaults to 80 if not specified
- scheme - the scheme to use, either HTTP or HTTPS, this defaults to HTTP if not specified
Forward can be further controlled using:
- the number of times the request is forwarded (including unlimited)
Java
To setup a forward in Java use the org.mockserver.model.HttpForward class which specifies the details of each HTTP(S) forward with a fluent API:
public class HttpForward {
/**
* The host or ip address to forward the request to i.e. "www.mock-server.com"
*
* @param host a hostname or ip address as a string
*/
public HttpForward withHost(String host);
/**
* The port to forward the request to i.e. 80. If not specified the port defaults to 80.
*
* @param port a port as an integer
*/
public HttpForward withPort(Integer port);
/**
* The scheme to use when forwarded the request, either HTTP or HTTPS. If not specified the scheme defaults to HTTP.
*
* @param scheme the scheme as a HttpForward.Scheme value
*/
public HttpForward withScheme(Scheme scheme);
}
For example:
HttpForward httpForward =
forward()
.withHost("www.mock-server.com")
.withPort(80)
.withScheme(HttpForward.Scheme.HTTP);
JavaScript
To mock a response in javascript use JSON to specify the details with the following format:
"httpForward": {
"host": "",
"port": 80,
"scheme": "HTTP"
}
The "scheme" value in can be:
"HTTP"
"HTTPS"
The same example as above would be:
"httpForward": {
"host": "www.mock-server.com",
"port": 80,
"scheme": "HTTP"
}
Callback
A callback specifies a class that will be called for each matching request and can be used to dynamically generate the response.
Callback actions contain:
- callbackClass
The callback class must:
- have a default constructor
- implement org.mockserver.mock.action.ExpectationCallback
- be available on the classpath (see below)
If MockServer is started using the JUnitRule org.mockserver.junit.MockServerRule or using org.mockserver.integration.ClientAndServer or directly using the org.mockserver.mockserver.MockServerBuilder then any class present in the main or test classpaths will be visible to MockServer.
If MockServer is started using the plugin only the non-forked goals (such as runAndWait and start) will be able to load classes from the main and test classpaths. It is possible to use classes from a separate maven dependency, however, this dependency must be specified in the plugin configuration dependencies section. Any dependency added to the plugin configuration dependencies section will then be visible to MockServer run using both forked and non-forked goals.
The following configuration shows how to use classes from a separate maven dependency in callback actions.
<plugin>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-maven-plugin</artifactId>
<version>3.9.9</version>
<configuration>
<serverPort>1080</serverPort>
<logLevel>DEBUG</logLevel>
<pipeLogToConsole>true</pipeLogToConsole>
</configuration>
<executions>
<execution>
<id>pre-integration-test</id>
<phase>pre-integration-test</phase>
<goals>
<goal>runForked</goal>
</goals>
</execution>
<execution>
<id>post-integration-test</id>
<phase>post-integration-test</phase>
<goals>
<goal>stopForked</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.my-domain</groupId>
<artifactId>my-callback-dependency</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</plugin>
If MockServer is started using the command line then the callback classes must be added to the JVM using the classpath command line switch (cp or classpath). The classpath switch is ignored by the JVM if the jar switch is used. So to run the MockServer from the command line directly (with mockserver-netty-3.9.9-jar-with-dependencies.jar) you must specify the org.mockserver.cli.Main main class specifically and not use the jar switch as follows.
java -Dfile.encoding=UTF-8 -cp mockserver-netty-3.9.9-jar-with-dependencies.jar:my-callback-dependency.jar org.mockserver.cli.Main -serverPort 1080
Java
To setup a callback in Java use the org.mockserver.model.HttpCallback class which specifies the details class to callback as follows:
public class HttpCallback {
/**
* The class to callback as a fully qualified class name
*
* This calls must:
* - implement org.mockserver.mock.action.ExpectationCallback
* - have a zero argument constructor
* - be available in the classpath of the MockServer
*
* @param callbackClass class to callback as a fully qualified class name, i.e. "com.foo.MyExpectationCallback"
*/
public HttpCallback withCallbackClass(String callbackClass);
}
The class specified must implement the org.mockserver.mock.action.ExpectationCallback interface as follows:
public interface ExpectationCallback {
/**
* Called for every request when expectation condition has been satisfied.
* The request that satisfied the expectation condition is passed as the
* parameter and the return value is the response that will be returned to the client.
*
* @param httpRequest the request that satisfied the expectation condition
* @return the response that will be returned to the client
*/
public HttpResponse handle(HttpRequest httpRequest);
}
JavaScript
To setup a callback in javascript use JSON to specify the details with the following format:
"httpCallback": {
"callbackClass": "org.mypackage.MyCallbackClass"
}
Verifying Behaviour
Request can be verified in two ways:
- MockServer - MockServer records all requests made to MockServer and can be used to verify which requests have been made
- Proxy - the proxy records all requests that are proxied and can be used to verify which requests have been made
MockServer Verification
The MockServer allows the verification of requests by specifying:
- an amount of a single type of request
- a sequence of requests that is verified in order
Verifying Repeating Requests
To verify that the system under test has sent an inidividual request to MockServer use the verify method of the MockServerClient as follows:
new MockServerClient("localhost", 9090).verify(
request()
.withMethod("POST")
.withPath("/login")
.withBody(exact("{username: 'foo', password: 'bar'}"))
.withCookies(
new Cookie("sessionId", ".*")
),
VerificationTimes.exactly(1)
);
The org.mockserver.verify.VerificationTimes class is used to specify how many times you want MockServer to match a request:
To create an instance of VerificationTimes use one of the static factory methods:
VerificationTimes.once();
VerificationTimes.exactly(int count);
VerificationTimes.atLeast(int count);
Verifying Request Sequences
To verify that the system under test has sent a sequence of requests to MockServer use the verify method of the MockServerClient as follows:
new MockServerClient("localhost", 9090).verify(
request()
.withMethod("POST")
.withPath("/login")
.withBody(exact("{username: 'foo', password: 'bar'}"))
.withCookies(
new Cookie("sessionId", ".*")
),
request()
.withMethod("POST")
.withPath("/deposit")
.withBody(exact("{acccount: '123456789', card: '1234 5678 9012 3456', amount: '10.00'}"))
.withCookies(
new Cookie("sessionId", ".*")
),
request()
.withMethod("POST")
.withPath("/logout")
.withCookies(
new Cookie("sessionId", ".*")
)
);
The each request in the sequence will be verified to have been received at least once, in the exact order specified.
Proxy Verification
The proxy supports exactly the same features for verifying requests described above for the MockServer.
However, with the proxy, it it also possible to verify requests being sent to other HTTP/HTTPS endpoints. To do this the system under test must be configured to use the proxy. The proxy will then all outgoing and request and responses.
The following examples show how to do this with different HTTP clients:
Jetty HttpClient 9.x
HttpClient httpClient = new HttpClient();
try {
httpClient.getProxyConfiguration().getProxies().add(new HttpProxy("localhost", 9090));
httpClient.start();
} catch (Exception e) {
throw new RuntimeException("Exception creating HttpClient", e);
}
Jetty HttpClient 8.x
HttpClient httpClient = new HttpClient();
try {
httpClient.setProxy(new Address("localhost", 9090));
httpClient.start();
} catch (Exception e) {
throw new RuntimeException("Exception creating HttpClient", e);
}
The mockserver-example project contains an example of using the proxy with Jetty HttpClient called BookServiceJettyHttpClient that demonstrates a fully working example.
Apache HttpClient
HttpHost httpHost = new HttpHost("localhost", 9090);
DefaultProxyRoutePlanner defaultProxyRoutePlanner = new DefaultProxyRoutePlanner(httpHost);
HttpClient httpClient = HttpClients.custom().setRoutePlanner(defaultProxyRoutePlanner).build();
The mockserver-example project contains an example of using the proxy with Apache HttpClient called BookServiceApacheHttpClient that demonstrates a fully working example.
Jersey
ClientConfig clientConfig = new ClientConfig().register(new JacksonFeature())
.connectorProvider(new ApacheConnectorProvider());
clientConfig.property(ClientProperties.PROXY_URI, "http://localhost:9090");
Client client = ClientBuilder.newClient(clientConfig);
The mockserver-example project contains an example of using the proxy with Jersey called BookServiceJerseyClient that demonstrates a fully working example.
Spring Rest Template
RestTemplate restTemplate = new RestTemplate();
HttpHost httpHost = new HttpHost("localhost", 9090);
DefaultProxyRoutePlanner defaultProxyRoutePlanner = new DefaultProxyRoutePlanner(httpHost);
HttpClient httpClient = HttpClients.custom().setRoutePlanner(defaultProxyRoutePlanner).build();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
The mockserver-example project contains an example of using the proxy with Spring Rest Template called BookServiceSpringRestTemplateClient that demonstrates a fully working example.
Grizzly
AsyncHttpClientConfig.Builder clientConfigBuilder = new AsyncHttpClientConfig.Builder();
clientConfigBuilder.setProxyServerSelector(ProxyUtils.createProxyServerSelector(HttpProxy.proxySelector()));
AsyncHttpClient asyncHttpClient = new AsyncHttpClient(clientConfigBuilder.build());
The mockserver-example project contains an example of using the proxy with Grizzly Http Client called BookServiceGrizzlyHttpClient that demonstrates a fully working example.
To verify that a request has been sent use the verify method of the ProxyClient as follows:
new ProxyClient("localhost", 9090).verify(
request()
.withMethod("POST")
.withPath("/login")
.withBody(exact("{username: 'foo', password: 'bar'}"))
.withCookies(
new Cookie("sessionId", ".*")
),
VerificationTimes.exactly(1)
);
The mockserver-example project contains an example test called BookPageIntegrationTest that demonstrates a fully working example.
Analysing Behaviour
To analyse the requests that system makes the proxy can be used to record all requests and write them into the mockserver_request.log. This can be particularly helpful when refactoring an existing or legacy system.
The requests can be written to the log in JSON or as Java code. The Java code can then be used to setup expectations in MockServer and exactly replay all interactions.
First the system that is being analysed must be configured to use the proxy.
If the proxy is being started programmatically from within the same JVM using org.mockserver.proxy.ProxyRunner or org.mockserver.integration.ClientAndProxy then the environment variables for "proxySet", "http.proxyHost" and "http.proxyPort" will be set automatically.
If the proxy is being started as separate JVM, for example using the command line, then the system being analysed needs the following command line options to set the correct environment variables.
-DproxySet=true -Dhttp.proxyHost=<proxy hostname> -Dhttp.proxyPort=<proxy port>
For example:
-DproxySet=true -Dhttp.proxyHost=localhost -Dhttp.proxyPort=9090
Apache HttpClient
To configure the proxy with an Apache HttpClient, as follows:
public HttpClient createHttpClient() {
if (Boolean.parseBoolean(System.getProperty("proxySet"))) {
HttpHost httpHost = new HttpHost(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort")));
DefaultProxyRoutePlanner defaultProxyRoutePlanner = new DefaultProxyRoutePlanner(httpHost);
return HttpClients.custom().setRoutePlanner(defaultProxyRoutePlanner).build();
} else {
return HttpClients.custom().build();
}
}
The mockserver-example project contains an example of using the proxy with a Apache HttpClient called BookServiceApacheHttpClient that demonstrates a fully working example.
Grizzly AsyncHttpClient
To configure the proxy with a Grizzly AsyncHttpClient, as follows:
public AsyncHttpClient createHttpClient() {
AsyncHttpClientConfig.Builder clientConfigBuilder = new AsyncHttpClientConfig.Builder();
if (Boolean.parseBoolean(System.getProperty("proxySet"))) {
clientConfigBuilder.setProxyServerSelector(ProxyUtils.createProxyServerSelector(ProxyRunner.proxySelector()));
}
return new AsyncHttpClient(clientConfigBuilder.build());
}
The mockserver-example project contains an example of using the proxy with a Grizzly AsyncHttpClient called BookServiceGrizzlyHttpClient that demonstrates a fully working example.
Jersey Client
To configure the proxy with a Jersey Client, as follows:
public Client createHttpClient() {
ClientConfig clientConfig = new ClientConfig()
.register(new JacksonFeature())
.connectorProvider(new ApacheConnectorProvider());
if (Boolean.parseBoolean(System.getProperty("proxySet"))) {
clientConfig.property(ClientProperties.PROXY_URI, "http://" + System.getProperty("http.proxyHost") + ":" + System.getProperty("http.proxyPort"));
}
return ClientBuilder.newClient(clientConfig);
}
The mockserver-example project contains an example of using the proxy with a Jersey Client called BookServiceJerseyClient that demonstrates a fully working example.
Jetty HttpClient
To configure the proxy with a Jetty HttpClient, as follows:
public HttpClient createHttpClient() {
HttpClient httpClient = new HttpClient();
try {
if (Boolean.parseBoolean(System.getProperty("proxySet"))) {
httpClient.getProxyConfiguration().getProxies().add(new HttpProxy(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort"))));
}
httpClient.start();
} catch (Exception e) {
throw new RuntimeException("Exception creating HttpClient", e);
}
return httpClient;
}
The mockserver-example project contains an example of using the proxy with a Jetty HttpClient called BookServiceJettyHttpClient that demonstrates a fully working example.
Spring RestTemplate
To configure the proxy with a Spring RestTemplate, as follows:
public RestTemplate createRestTemplate() {
// jackson message converter
MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJacksonHttpMessageConverter();
mappingJacksonHttpMessageConverter.setObjectMapper(objectMapper);
// create message converters list
List<HttpMessageConverter<?>> httpMessageConverters = new ArrayList<>();
httpMessageConverters.add(mappingJacksonHttpMessageConverter);
// create rest template
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(httpMessageConverters);
// configure proxy
if (Boolean.parseBoolean(System.getProperty("proxySet"))) {
HttpHost httpHost = new HttpHost(
System.getProperty("http.proxyHost"),
Integer.parseInt(System.getProperty("http.proxyPort"))
);
DefaultProxyRoutePlanner defaultProxyRoutePlanner = new DefaultProxyRoutePlanner(httpHost);
HttpClient httpClient = HttpClients.custom().setRoutePlanner(defaultProxyRoutePlanner).build();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
}
return restTemplate;
}
The mockserver-example project contains an example of using the proxy with a Spring RestTemplate called BookServiceSpringRestTemplateClient that demonstrates a fully working example.
Write Requests To Log
Write the recorded request to the log as Java code, as follows:
new ProxyClient("localhost", 9090).dumpToLogAsJava(
request()
.withMethod("POST")
.withPath("/login")
);
The Java code format that requests are written to the logs is as follows:
2014-01-12 21:46:33,305
new MockServerClient()
.when(
request()
.withMethod("GET")
.withPath("/get_book")
.withQueryString("id=1")
.withHeaders(
new Header("Accept-Encoding", "gzip"),
new Header("Host", "localhost:1090"),
new Header("User-Agent", "Jetty/8.1.13.v20130916")
),
Times.once()
)
.thenRespond(
response()
.withStatusCode(200)
.withHeaders(
new Header("Server", "Jetty(8.1.13.v20130916)")
)
.withBody("{\n \"id\": \"1\",\n \"title\": \"Xenophon's imperial fiction : on the education of Cyrus\",\n \"author\": \"James Tatum\",\n \"isbn\": \"0691067570\",\n \"publicationDate\": \"1989\"\n }")
);
Write the recorded request to the log as JSON, as follows:
new ProxyClient("localhost", 9090).dumpToLogAsJSON(
request()
.withMethod("POST")
.withPath("/login")
);
The JSON format that requests are written to the logs is as follows:
2014-01-12 21:46:33,299 {
"httpRequest" : {
"method" : "GET",
"path" : "/get_book",
"queryString" : "id=1",
"headers" : [
{
"name" : "Accept-Encoding",
"values" : [ "gzip" ]
},
{
"name" : "Host",
"values" : [ "localhost:8080" ]
},
{
"name" : "User-Agent",
"values" : [ "Jetty/8.1.13.v20130916" ]
} ]
},
"httpResponse" : {
"statusCode" : 200,
"body" : "{\n \"id\": \"1\",\n \"title\": \"Xenophon's imperial fiction : on the education of Cyrus\",\n \"author\": \"James Tatum\",\n \"isbn\": \"0691067570\",\n \"publicationDate\": \"1989\"\n}",
"headers" : [ {
"name" : "Server",
"values" : [ "Jetty(8.1.13.v20130916)" ]
} ]
},
"times" : {
"remainingTimes" : 1,
"unlimited" : false
}
}
Running Tests In Parallel
To ensure all tests can run in parallel with completely isolated independent data it is important to include a value unique to each test for the request matcher.
For example the code above has a sessionId cookie in the request matcher. If each test generates a different value (i.e. a UUID) for the sessionId cookie then each test can receive completely independent response. Instead of a cookie value a query parameter or header (such as the Referer header) can also be used to ensure mock responses are unique to each test.
Clear & Reset
To clear all expectations (without restarting) use reset as follows:
Java
mockServerClient.reset()
JavaScript
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("PUT", "http://localhost:9999/reset", false);
xmlHttpRequest.send();
To clear only specific expectations use clear as follows:
Java
mockServerClient.clear(
request()
.withMethod("POST")
.withPath("/login")
);
JavaScript
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("PUT", "http://localhost:9999/clear", false);
xmlHttpRequest.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xmlHttpRequest.send(JSON.stringify({
"method": "POST",
"path": "/login",
}));
The example above clears all expectations that will match incoming requests with a POST method on the path /login.
Debugging Issues
To simplify debugging MockServer expectations can be dumped to the log at WARN level using pretty-printed JSON.
To dump all expectations to the log use dumpToLog as follows:
Java
mockServerClient.dumpToLog()
JavaScript
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("PUT", "http://localhost:9999/dumpToLog", false);
xmlHttpRequest.send();
To dump only specific expectations to the log use dumpToLog as follows:
Java
mockServerClient.dumpToLog(
request()
.withMethod("POST")
.withPath("/login")
);
JavaScript
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("PUT", "http://localhost:9999/dumpToLog", false);
xmlHttpRequest.send(JSON.stringify({
"method": "POST",
"path": "/login",
}));
The example above dumps all expectations that match incoming requests with a POST method on the path /login.
Requirements
- Java 6+ to use the Netty version, the Maven Plugin and MockServer WAR and proxy WAR
- Java 7+ to use the Vert.X module or the Embedded Jetty version as both Jetty 9 and Vert.X in turn require Java 7 (Note: all features provided in the Embedded Jetty version are also available using the Netty version)
Downloads
The simplest way to run and download MockServer is by using the fully stand alone web server embedded with all dependencies that mocks HTTP and HTTPS requests, as follows:
download mockserver-netty-3.9.9-jar-with-dependencies.jar from Maven Central
-
java -jar <path to mockserver-netty-3.9.9-jar-with-dependencies.jar> -serverPort <port>
For more details on downloads see:
jar-with-dependencies / jar / war packages at MockServer on Maven Central.
Vert.X Modules at MockServer on Vert.X Module Registry.
source code at MockServer on GitHub.
GitHub
The source control for MockServer is git which is hosted at GitHub jamesdbloom/mockserver
GitHub is also used to track issues / bugs and manage pull-requests.
Maven Central
Maven Central contains the following MockServer artifacts:
- mockserver-netty - a web server for mocking and proxying using Netty, can be added to a maven build as follows:
<dependency> <groupId>org.mock-server</groupId> <artifactId>mockserver-netty</artifactId> <version>RELEASE</version> </dependency>
- mockserver-netty:jar-with-dependencies - as above using Netty that includes all dependencies are bundled into the jar file, this artifact can be downloaded.
- mockserver-war - a deployable WAR for mocking that can be deployed to any JEE web server, this artifact can be downloaded.
- mockserver-proxy-war - a deployable WAR for proxying that can be deployed to any JEE web server, this artifact can be downloaded.
- mockserver-maven-plugin - a set of maven plugins to start, stop and fork MockServer using maven, can be added to a maven build as follows:
<plugin> <groupId>org.mock-server</groupId> <artifactId>mockserver-maven-plugin</artifactId> <version>RELEASE</version> <configuration> <serverPort>1080</serverPort> <pipeLogToConsole>true</pipeLogToConsole> </plugin>
- mockserver-client-java - a Java client to communicate with both the server and the proxy, can be added to a maven build as follows:
<dependency> <groupId>org.mock-server</groupId> <artifactId>mockserver-client-java</artifactId> <version>RELEASE</version> </dependency>
In addition the continuous integration build on Travis deploys a SNAPSHOT version on every github commit these SNAPSHOT artifacts can be found at https://oss.sonatype.org/index.html#nexus-search;quick~mockserver by adding the correct repository to maven:
<repositories>
<repository>
<id>sonatype-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
then specifying the latest SNAPSHOT build, for example for mockserver-netty this would be as follows:
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-netty</artifactId>
<version>SNAPSHOT</version>
</dependency>
Ruby Gems
Ruby Gems contains the following gems:
- mockserver-client - ruby client for MockServer and proxy
Node Packaged Modules (npm)
npm contains the following modules:
- mockserver-grunt - node module and grunt taks to start and stop MockServer and its proxy
- mockserver-client - node client for MockServer and its proxy
Vert.X Module Registry
Vert.X Module Registry contains the following artifacts:
- org.mock-server~mockserver-vertx~2.9 - a Vert.X module that mocks HTTP and HTTPS requests
Vert.X Module Registry will shortly also have the following artifacts:
- org.mock-server~mockserver-vertx-proxy~2.9 - a Vert.X module that proxies HTTP and HTTPS allowing the recording and querying of requests and responses
Docker Container
MockServer is available as a docker container that allows you to easily run MockServer as a separate container on any environment without having to install Java or any other libraries. The docker container fully encapsulates all requirements required to run MockServer (such as Java) and separates the running MockServer instance from all other parts of the system.
MockServer docker container can be found at MockServer Docker
Travis CI
Travis CI is used for the continuous integration. The build uses both Java 1.6, Java 1.7 and Java 1.8 to build the different modules in their appropriate java version, the latest SNAPSHOT is also deployed to Sonatype.
The status of the build is shown at the top of this page and on the github project using the Travis CI logo
drone.io
drone.io is an alternative continuous integration platform also being used. Currently Travis CI and drone.io are both being used to determine which platform works better for MockServer.
The status of the drone.io build is as follows:
Backlog
Waffle is used to visualise the backlog, although all the items are stored in Github.
The following icons shows the status of the backlog:
Site Map
- What Is Mockserver
- Why Use Mockserver
- Getting Started
- Mocking Overview
- Proxying Overview
- MockServer & Proxy Versions
- Clients
- Starting Mockserver
- Create Expectations
- Verify Behaviour
- Analysing Behaviour
- Ensuring Tests Can Run In Parallel
- Clear & Reset
- Debugging Issues
- Requirements
- Versions
- Continuous Integration
- Backlog


What is Lorem Ipsum? Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
e'wqe wq el;/ew qeqw el;qw/e.qwheQWewqe wq'ehgwqvc el/qen qwrqwR'qw;'qwqwe qw'.ww