In unit testing we often mock various objects, libraries and side effects. For example it can be a response from some web service. But what should we do in integration and functional tests?

The problem

Let’s imagine that your application receives data from a third-party web service and you want to run integration tests. Running tests against the real web service is not the best idea. You probably need to provide credentials and maybe other sensitive data that doesn’t make sense to pass into a testing environment. A good approach would be set up a fake web server that can emulate behavior of the real third-party service.

The solution

I found an interesting piece of software called MockServer. Let me quote the description from the official site:

For any system you integrate with via HTTP or HTTPS MockServer can be used as:

  • a mock configured to return specific responses for different requests
  • a proxy recording and optionally modifying requests and responses
  • both a proxy for some requests and a mock for other requests at the same time

When MockServer receives a request it matches the request against active expectations that have been configured, if no matches are found it proxies the request if appropriate otherwise a 404 is returned.

For each request received the following steps happen:

  • find matching expectation and perform action
  • if no matching expectation proxy request
  • if not a proxy request return 404

Sounds pretty cool. Let me share how I used it in one of my pet projects.

Usage

In order to start using MockServer you should define which endpoints you would like to mock. Perhaps you will need to modify the code of your application to have the ability to configure a proxy server. Then you need to record requests and responses using built-in proxy of MockServer. Just run the server:

java -jar mockserver-netty-5.11.2-jar-with-dependencies.jar -serverPort 8080

And configure system proxy to http://localhost:8080/. Send some requests via proxy and then you can download recorded requests and responses via MockServer REST API:

curl -X PUT "http://localhost:8080/mockserver/retrieve?type=REQUEST_RESPONSES"

The output is just a json with the following structure:

[
  {
    "httpRequest": {
      "method": "GET",
      "path": "/some/endpoint"
    },
    "httpResponse": {
      "statusCode": 200,
      "reasonPhrase": "OK",
      "body": {
        "status": 200,
        ...
        }
      }
    }
  },
  ...
]

The replay contains a lot of request and responses aspects such as cookies, various headers and so on. You might not need to store all of them therefore feel free to edit the file to keep only required data. After that you can use this file in your tests. Run the MockServer and specify the path to the replay file:

export MOCKSERVER_INITIALIZATION_JSON_PATH=<path to replay file>
java -jar mockserver-netty-5.11.2-jar-with-dependencies.jar -serverPort 8080

When your application sends a request to the third-party web service via MockServer proxy it will get exactly the same responses that you specified in httpResponse stanzas.

HTTPS & TLS

Nowadays almost all web applications work only wih HTTPS. It means that you cannot intercept traffic between the client and the server. MockServer is able to mock the behaviour of multiple hostnames and present a valid X.509 Certificates for them. MockServer achieves this by dynamically generating its X.509 Certificate using an in-memory list of hostnames and ip addresses. Create a mockserver.properties file with the following content:

###############################
# MockServer & Proxy Settings #
###############################

# Certificate Generation

# dynamically generated CA key pair (if they don't already exist in specified directory)
mockserver.dynamicallyCreateCertificateAuthorityCertificate=true
# save dynamically generated CA key pair in working directory
mockserver.directoryToSaveDynamicSSLCertificate=.
# certificate domain name (default "localhost")
mockserver.sslCertificateDomainName=localhost
# comma separated list of ip addresses for Subject Alternative Name domain names (default empty list)
mockserver.sslSubjectAlternativeNameDomains=<third-party web service host name>

Run the MockServer:

export MOCKSERVER_PROPERTY_FILE=mockserver.properties
java -jar mockserver-netty-5.11.2-jar-with-dependencies.jar -serverPort 8080

And after that you will find two new files: CertificateAuthorityCertificate.pem and PKCS8CertificateAuthorityPrivateKey.pem. We should add MockServer’s CA into the system list of trusted Certificate Authorities. The following commands are applicable for Ubuntu:

sudo cp CertificateAuthorityCertificate.pem /usr/local/share/ca-certificates/MockServer.crt
sudo update-ca-certificates

WARNING! Remember if you add a new Certificate Authority into your system the issuer can listen to your traffic. Do not install random CAs from the internet!

In case of MockServer it’s safe because you are the issuer :).

After these procedures MockServer will be able to record requests and responses to any HTTPS resource.

Conclusion

MockServer is a powerful tool that gives unlimited ability for creating fake APIs of any web service. I described a small amount of its features and abilities because MockServer really can do a lot. More details you will find in very good documentation on the official site.

References:

Discuss on Github