ServiceMock

ServiceMock is a Ruby gem that provides a wrapper over the WireMock library. The gem provides the ability to perform many actions on a WireMock instance including starting, stopping, and several ways to stub out calls. It is highly recommended that you take the time to read the WireMock documentation and understand the how the library works.

This gem can be used to help you virtualize services for your tests. For example, if you are unable to achieve effective test data management with the backend systems you can use this gem (with WireMock) to simulate (or mock) the services while controlling the data that is returned.

ServiceMock also provides two built-in rake task that can be used to start and stop an instance of WireMock. The rake task need to be executed on the machine that the server will run - there is no ability for remote start and stop.

Usage

Using the API

All interaction with the WireMock services is via calls to an instance of ServiceMock::Server. On your local machine you can start and stop an instance of the server process. On local and remove machines you can also use one of several methods to create stubs (specify request/response data) as well as tell the server to save in-memory stubs, reset_mappings to remove all of the stubs you have provided and reset_all which completely clears all mappings and files that you have setup for WireMock to return as your system under test interacts with it.

When you create your instance of ServiceMock::Server you need to provide some information. The required piece of data is the version of WireMock you will be using. If the name of the WireMock jar file you will be using is wiremock-standalone-2.0.10-beta.jar then the version you should provide is standalone-2.0.10-beta. In other words, take off the initial wiremock- and the trailing .jar and this is your version. The other optional value you can provide is the working directory - the location where the WireMock jar is located. By default the working directory is set to config/mocks. You will initialize the server like this:

# uses default working directory
my_server = ServiceMock::Server.new('standalone-2.0.10-beta')

# or this sets the working directory
my_server = ServiceMock::Server.new('standalone-2.0.10-beta', '/path/to/jar')

There are two additional values (inherit_io and wait_for_process) that are defaulted to false. If set to true, inherit_io will cause our instance to 'inherit' the standard out and in for the running WireMock process. When wait_for_process is set to true it will cause the call to start to block until the underlying WireMock process exits. These values can be overwritten in the call to start as described below.

Starting the Server

You start the server by calling the start method but it doesn't end there. There are a large number of parameters you can set to control the way that WireMock runs. These are set via a block that is passed to the start method.

my_server.start do |server|
  server.port = 8081
  server.record_mappings = true
  server.root_dir = /path/to/root
  server.verbose = true
end

The values that can be set are:

value description
port The port to listen on for http request
https_port The port to listen on for https request
https_keystore Path to the keystore file containing an SSL certificate to use with https
keystore_password Password to the keystore if something other than "password"
https_truststore Path to a keystore file containing client certificates
truststore_password Optional password to the trust store. Defaults to "password" if not specified
https_reuire_client_cert Force clients to authenticate with a client certificate
verbose print verbose output from the running process. Values are true or false
root_dir Sets the root directory under which mappings and __files reside. This defaults to the current directory
record_mappings Record incoming requests as stub mappings
match_headers When in record mode, capture request headers with the keys specified
proxy_all proxy all requests through to another URL. Typically used in conjunction with record_mappings such that a session on another service can be recorded
preserve_host_header When in proxy mode, it passes the Host header as it comes from the client through to the proxied service
proxy_via When proxying requests, route via another proxy server. Useful when inside a corporate network that only permits internet access via an opaque proxy
enable_browser_proxy Run as a browser proxy
no_request_journal Disable the request journal, which records incoming requests for later verification
max_request_journal_entries Sets maximum number of entries in request journal. When this limit is reached oldest entries will be discarded

In addition, as mentioned before, you can set the inherit_io and wait_for_process options to true inside of the block.

Stubbing service calls

Please read the WireMock stubbing documentation so you understand the message structures that are used. It is very important that you understand this first. Those details will not be covered here.

There are three methods that can be used to stub services.

my_server.stub(string_containing_json_stub)

my_server.stub_with_file(file_containing_json_stub)

my_server.stub_with_erb(erbfile_containing_json_stub, hash_with_values)

The first method is pretty self-explanatory. You simply pass a string that contains the json stub and the server contacts the running server process and sets it up. The second method takes a full path to a file that contains the json stub.

The third method is where things get interesting. It allows you to provide an ERB file that will become your json stub. ERB stands for Embedded Ruby and allows you to insert Ruby code inside any type of file - including json. Using this ability to allows us to build templates of the service messages. It is quite common to mock a service many times and while the structure is the same with each mock the data supplied and returned is different. Using templates allows us to simply write the template once and then supply the data for each mock.

The third method takes the full path to an erb file that contains the json stub and a Hash that contains key=>value combinations that will fill in the data elements in the template.

If you set the port value when you started the server you will need to do the same via a block when stubbing.

my_server.stub(string_containing_json_stub) do |server|
  server.port = 8081
end

Stubbing multiple services

It is often necessary to stub multiple service calls in order to complete a test. ServiceMock has created a simple way to do this. It is implemented in a class named ServiceMock::StubCreator. This class has a single public method create_stubs_with which takes the name of the name of a file that has the data for all of the stubs you wish to create and optional data to merge with that file. Also, when you create an instance of the class it requires you to pass an instance of ServiceMock::Server.

At this time you need to setup everything in a specific directory structure. The directory it looks for is config/mocks/stubs. Inside that directory it looks for two additional directories - data and templates. The data file needed by the call needs be located in the data directory and the ERB files (templates) that it references needs to be in the templates directory.

The structure of the data file drives the stubbing. Let's start with an example.

service1.erb:
  first_name: Mickey
  last_name: Mouse

service2.erb:
  username: mmouse
  password: secret

With the above file the method call will mock to services. It will first of all read the file service1.erb from the templates directory and stub it passing the data that is associated. Next it will read the next template file, etc.

Other capabilities

There are additional methods that provide access to the running WireMock server. If you changed the port during startup then you will need to do so here as well. The methods are:

my_server.stop

Stops the running WireMock server if it is running locally.

my_server.save

Writes all of the stubs to disk so they are available the next time the server starts.

my_server.reset_mappings

Removes the stubs that have been created since WireMock was started.

my_server.reset_all

Removes all stubs, file based stubs, and request logs from the WireMock server.

Using the Rake Tasks

There are two rake tasks that are provided to make it easy to start and stop the WireMock server when working locally. You can simply add the following to your Rakefile:

require 'service_mock'
require 'service_mock/rake/rake_tasks'

WIREMOCK_VERSION = 'standalone-2.0.10-beta'
ServiceMock::Rake::StartServerTask.new(:start_server, WIREMOCK_VERSION)
ServiceMock::Rake::StopServerTask.new(:stop_server, WIREMOCK_VERSION)

Any parameter that can be passed to the start method can also be passed to the rake task.

ServiceMock::Rake::StartServerTask.new(:start_server, WIREMOCK_VERSION) do |server|
  server.port = 8081
  server.record_mappings = true
  server.root_dir = /path/to/root
  server.verbose = true
end

If you set the port in the start task then you will also need to set it in the stop task.

ServiceMock::Rake::StopServerTask.new(:stop_server, WIREMOCK_VERSION) do |server|
  server.port = 8081
end

Installation

Add this line to your application's Gemfile:

gem 'service_mock'

And then execute:

$ bundle

Or install it yourself as:

$ gem install service_mock

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/cheezy/service_mock. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.