Vladimir Dyuzhev
MockMotor Creator
How to Record and Mock REST Traffic with MockMotor
When recording a REST call, MockMotor automatically finds parameters in the request URL.
REST traffic is not very different from HTTP traffic. This is not a surprise since REST is HTTP.
However, in a REST service call, the URL can contain segments that are actual parameters.
An account parameter that in HTTP is encoded as http://service?account=100500
, in the pure REST would be http://service/account/100500
.
This is not a dogma, and a REST service can use the query string, just as an HTTP service can have parameters in the URL.
MockMotor doesn't make a difference between REST and HTTP traffic when recording. However, it tries to find parameters in URL components and assign them reasonable names.
Let's see how MockMotor records REST.
Why Record at All?
Why do we need to record? Can't we just use the live service?
Well, there could be multiple very good reasons.
- We may want to stay within the free account requests quota.
- We may need to test special cases, such as errors or slow responses.
- We may alter some response data to adjust them for our scenarios.
- We may want to have a stable set of accounts to reuse for regression testing.
- We may want to run load tests.
The Goal: Record a REST Service
Let's record a live REST service.
Our recording should:
- Intercept calls with parameters, including those in URL components
- Forward these calls to the live backend
- Record the responses as mocks
- Configure those mocks to match the original requests
The Backend: US National Library of Medicine's RxNorm
RxNorm is a service for medical applications. It allows for obtaining tonnes of special information about medications presented on the US market. See for yourself.
For us, however, it has two useful properties:
- It's free to call
- Its request URLs contain parameters
A typical request looks like this:
https://rxnav.nlm.nih.gov/REST/rxcui/18600/allProperties.json?prop=all
Here 18600
is a RxCUI code for azatadine
.
The response is a rather large JSON payload that contains all properties for this substance:
{"propConceptGroup": {"propConcept": [
{
"propCategory": "ATTRIBUTES",
"propName": "TTY",
"propValue": "IN"
},
{
"propCategory": "ATTRIBUTES",
"propName": "PRESCRIBABLE",
"propValue": "Y"
},
{
"propCategory": "CODES",
"propName": "RxCUI",
"propValue": "18600"
},
{
"propCategory": "CODES",
"propName": "NUI",
"propValue": "N0000007088"
},
...
Needless to say, the responses for /rxcui/18600/
and say /rxcui/7052/
(morphine) are very different. When recording mocks for this backend, we should create two
different mocks - one matching 18600
and another matching 7052
(and then maybe dozens more matching other substances used in test runs).
Let's proceed.
Create a Service
First, let's create a test service that is going to mock RxNorm.
Nothing special is required. We assign it a relative URL of /RxNorm
, and the full mock service URL is seen at the top of the page:
Create a Forward Response
Now its time to add a forwarding/recording response to the service.
- It should match
GET
HTTP operation (all RxNorm calls useGET
) - It should match any relative URL.
- It should have the RxNorm service's URL base set in the Forward field -
https://rxnav.nlm.nih.gov/REST/
- It should have
Recording
enabled.
Below is the forward response. Not important properties are hidden.
In the responses list, the forwarding response looks like this:
Now, when we call this mock service, the forwarding response calls the live backend with our payload and records the response as a mock.
Record the Responses
Let's run a few test cases that get information for RxCUIs via our mock service.
Here is a call for Azatadine information:
http://127.0.0.1:20072/RxNorm/rxcui/18600/allProperties.json?prop=all
Since we do not have any local mocks yet, the request is handled by the forwarding mock response. It sends the request to the actual RxNorm backend. When the backend responds, MockMotor records the response properties as a new mock.
MockMotor sees that the request payload is not XML (in fact, the payload is missing because it is an HTTP GET) and decides it must be an HTTP/REST call.
For the HTTP part, it finds the prop=all
HTTP query parameter and adds it to the match script as http.parameter.prop=="all"
.
For the REST part, MockMotor analyzes the URL, trying to find any sequence that looks like a name/value pair. It is not always easy, but
for our URL, the /rxcui/18600
sequence is very likely a key and a value.
MockMotor hence defines the relative URL as
rxcui/{rxcui}/allProperties.json
so the REST parameter rxcui
gets its value from the URL component.
Lastly, MockMotor adds a condition rest.parameter.rxcui=="18600"
to the matching script so that only requests for 18600
match this new response.
Let's execute two more requests:
Morphine:
http://127.0.0.1:20072/RxNorm/rxcui/7052/allProperties.json?prop=all
Zithromax 500 MG Injection:
http://127.0.0.1:20072/RxNorm/rxcui/1668240/allProperties.json?prop=all
Review the Recorded Responses
Let's take a look at the service's responses again:
You can see that the forward mock has created three mock responses.
Each of the recorded mocks has its own version of the match script, containing its own specific values of RxCUI value, e.g.:
http.parameters.prop=="all" && rest.parameters.rxcui=="18600"
In addition to the response payload and the match script, MockMotor recorded:
- HTTP operation
GET
- Relative URL
rxcui/{rxcui}/allProperties.json
- HTTP status
200
- Content-Type
application/json
- The response payload for this RxCUI
- Response time
Test the Recorded Mocks
The newly recorded mocks are now handling the matching requests. If we repeat the same requests again, we can see that the RxNorm backend isn't called.
Once we collect all the responses we need for our test scenarios, we do not need to call the actual backend at all. When the backend has to be leased to a team, this can mean large savings.
You can see the complete service on the demo MockMotor instance.