![]() |
From Testing Microservices with Mountebank by Brandon Byars
This article discusses how Mountebank lets you to virtualize services for testing individual microservices.
|
Save 37% on Testing Microservices with Mountebank. Just enter code fccbyars into the discount code box at checkout at manning.com.
Once you understand how to integrate with a service, the next step is to figure out how to virtualize it for testing purposes. Let’s virtualize a sample Product Catalog service to test from the Web Façade in isolation:
Figure 1. Virtualizing the Product Catalog service to test the Web Façade
Remember, an imposter is the mountebank term for a virtual service. Mountebank imposters allow you to test individual microservices via virtualization. Mountebank ships with a REST API that lets us create imposters and write tests against them in any language.
Before we start, we’ll need to install mountebank. Several installation options are listed at www.mbtest.org/docs/install, but we’ll use npm
, a package manager that ships with node.js.
npm install -g mountebank
The -g
flag tells npm
to install mountebank globally, and you can run it from any directory. Let’s start it up:
mb
You should see the mountebank log on the terminal: info:
[mb:2525] mountebank v1.9.0 now taking orders - <linearrow /> point your browser to http://localhost:2525 for help
The log will prove invaluable in working with mountebank in the future, and it’s a good idea to familiarize yourself with it. The first word (info
, in this case), tells us the log level, which will be either debug
, info
, warn
, or error
. The part in brackets (mb:2525
) tells us the protocol and port, followed by the actual log message. The administrative port logs as the mb
protocol and starts on port 2525 by default (the mb
protocol’s HTTP, but mountebank logs it differently to make it easy to spot). The imposters we create use different ports but log to the same output stream in the terminal. The startup log message directs you to open localhost:2525
in your web browser, which provides you the complete set of documentations for your version of mountebank.
To demonstrate creating imposters, we’ll use a utility called curl
, which lets you make HTTP calls on the command line. curl
comes by default on most Unix-like shells, including Linux and OSX. You can install it on Windows using cygwin, or use PowerShell, which ships with modern versions of Windows (we’ll show a PowerShell example next). Open another terminal window and run the following command:[1]
curl – X POST http://localhost:2525/imposters --data ‘{ ❶ "port": 3000, ❷ "protocol": "http", ❷ "stubs": [{ ❸ "responses":[{ ❸ "is": { ❸ "statusCode": 200, ❸ "headers: {"Content-Type": "application/json"}, ❸ "body": { ❸ "products": [ ❸ { ❸ "id":"2599b7f4", ❸ "name”: "The Midas Dogbowl", ❸ "Description”: "Pure gold" ❸ }, ❸ { ❸ "id": "e1977c9e", ❸ "name": "Fishtank Amore", ❸ "description": "Show your fish some love" ❸ } ❸ ], ❸ "_links": { ❸ "Next: "/products?page=2&itemsPerPage=2" ❸ } ❸ } ❸ } ❸ }] }] }’
❶ A POST to localhost:2525/imposters is how you create new imposters
❷ Each imposter is minimally defined by a port and a protocol
❸ Defines a canned HTTP response based on the HTTP response format we looked at earlier
An important point to note is that we’re passing a JSON object as the body
field. As far as HTTP is concerned, a response body is a stream of bytes. Usually that stream is interpreted as a string, which is why mountebank typically expects a string as well. Mountebank supports binary response bodies, encoding them with Base64. That said, most services these days use JSON as their lingua franca. Mountebank, being itself a modern JSON-speaking service, can properly accept a JSON body
.The equivalent command on Powershell in Windows expects you to save the request body in a file and pass it to the Invoke-RestMethod
command. Save the JSON after the --data
parameter from the curl
command above into a file called imposter.json
, and run the following command from the same directory:
Invoke-RestMethod -Method POST -Uri http://localhost:2525/imposters <linearrow /> -InFile imposter.json
Notice what happens in the logs:
info: [http:3000] Open for business...
The part in brackets now shows the new imposter. As we add more imposters, this becomes increasingly important. All log entries can be disambiguated by looking at the imposter information that prefixes the log message.We can test our imposter on the command line as well, using the curl
command we looked at previously:
Figure 2. Using curl to send a request to our virtual Product Catalog service
The curl
command prints out the HTTP response as follows:
HTTP/1.1 200 OK Content-Type: application/json Connection: close Date: Thu, 19 Jan 2017 14:51:23 GMT Transfer-Encoding: chunked { "products": [ { "id":"2599b7f4", "name": "The Midas Dogbowl", "Description": "Pure gold" }, { "id": "e1977c9e", "name”: "Fishtank Amore", "description": "Show your fish some love" } ], "_links": { "Next: "/products?page=2&itemsPerPage=2" } }
A couple of extra headers are in there, and the date has changed, but otherwise the HTTP response is the same as the one returned by the service shown previously. We’re not accounting for all situations. Our imposter returns the same response no matter what the HTTP request looks like. We could fix that by adding predicates to our imposter configuration. As a reminder, a predicate is a set of criteria which the incoming request must match before mountebank sends the associated response. Let’s create an imposter with two products to serve up. It shows an empty result set on the request to the second page of results by using a predicate on the query parameter. For now, restart mb
to free up port 3000 by pressing Ctrl-C and typing mb
again (we’ll show more elegant ways of cleaning up after ourselves shortly). Then use this command in a separate terminal.
Curl – X POST http://localhost:2525/imposters --data ‘{ "port": 3000, "protocol": "http", "stubs": [ ❶ { "predicates": [{ "equals": { ❷ "query": { "page": "2" } ❷ } ❷ }], "responses": [{ "is": { ❸ "statusCode": 200, ❸ "headers": {"Content-Type": "application/json"}, ❸ "body": { "products": [] } } ❸ }] }, { "responses": [{ "is": { ❹ "statusCode": 200, ❹ "headers": { "Content-Type": "application/json" }, ❹ "body": { ❹ "products": [ ❹ { ❹ "id": "2599b7f4", ❹ "name": "The Midas Dogbowl", ❹ "description": "Pure gold" ❹ }, ❹ { ❹ "id": "e1977c9e", ❹ "name": "Fishtank Amore", ❹ "description": "Show your fish some love" ❹ } ❹ ], ❹ "_links": { ❹ "next": "/products?page=2&itemsPerPage=2" ❹ } ❹ } ❹ } ❹ }] } ] },
❶ Our imposter now has two stubs, allowing us different responses for different requests
❷ Requires that the request querystring includes page=2
❸ For requests matching the predicate, this response is sent
❹ Because this stub has no predicates, it matches all requests and its response is sent if the request hasn’t matched predicates in stubs earlier in the array
Exploring the mountebank API on the command line is a great way to get familiar with it and to try out sample imposter configurations. If we change the configuration of our Web Façade to point to localhost:3000
instead of api.petstore.com, we’ll get the products we’ve defined and can manually test the website. We’ve already taken the huge step of decoupling ourselves from the real services.
Postman as an alternative to the command line
While using command line tools like curl
are great for lightweight experimentation, it’s often useful to have a more graphical approach to organizing different HTTP requests. Postman (www.getpostman.com/) has proven to be an extremely useful tools for playing with HTTP APIs. It started out as a Chrome plugin, but now has downloads for Mac, Windows, and Linux. It lets you fill in the various HTTP request fields and save off requests for future use.That said, the benefit of service virtualization is in enabling automated testing of individual microservices. That’s what Mountebank is all about.
That’s all for this article.
For more, check out the whole book on liveBook here and see this Slideshare Presentation.
[1] To avoid carpal tunnel syndrome, you can download the source at github.com/bbyars/mountebank-in-action.