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.