<mockData>
Description
The <mockData>
tag sets up fake responses to HTTP requests made from the bot script (mock objects).
When automated tests are run and $http.query
is called from the script (or a shorthand method like $http.get
),
the test runner checks whether there is a corresponding <mockData>
tag in the test with the same parameters and request body as the ones passed to the HTTP request.
-
If such a tag exists and its URL and body match the expected ones, the test runner uses the response specified in
<mockData>
as the HTTP response body returned by the method call. -
If the script contains an
$http
method call but there is no corresponding<mockData>
, the HTTP request is assumed to have failed and returns no data. This will most likely result in the test case also being failed.
No actual HTTP requests are made during test runs.
integration="true"
attribute for the <test>
or <test-case>
elements
to allow the test runner to make real HTTP requests throughout the whole test or a single test case. In this case, specifying <mockData>
is not necessary.integration="true"
and run automated tests fairly frequently,
real HTTP requests can quickly drain your API usage quotas or have some other unintended consequences. It is recommended to use this attribute sparingly and reserve it for integration tests — tests specifically designed to verify the integration between the bot script and the HTTP API it relies on.
Structure
<mockData>
supports the following child elements.
Request URL and parameters
-
<query>
specifies the request URL. This element is required.- It has a
method
attribute — the HTTP verb used for executing the request. The default value isGET
. - The body of the
<query>
element contains the URL where the HTTP request is sent. It cannot be empty.
- It has a
-
<parameters>
contains values for interpolated URL parameters. This element is optional.
To specify variable values such as query parameters,
you can either put them directly within <query>
or use a separate <parameters>
element.
The <parameters>
child elements should be written as <parameter-name>parameter-value</parameter-name>
,
and all parameter values in <query>
should be substituted with placeholders like ${parameter-name}
.
&
with &
, <
with <
, >
with >
.- Parameters inside the URL
- Parameters separately from the URL
<mockData>
<query>https://httpbin.org/get?foo=bar&text="Hello, world!"</query>
<!-- ... -->
</mockData>
<mockData>
<query>https://httpbin.org/${endpoint}?foo=${foo}&text=${text}</query>
<parameters>
<endpoint>get</endpoint>
<foo>bar</foo>
<text>Hello, world!</text>
</parameters>
<!-- ... -->
</mockData>
Request body
The optional <body>
element contains the request body.
If the mock object has a <body>
child element, an additional check is performed when executing an HTTP request
to verify that the expected request body matches the one actually passed from the script.
The body of this element should be a JSON object or primitive expected to be passed in the request body.
The following optional attributes can be provided for the tag:
-
strictMatch
determines how strictly the mock object is matched against the actual request body. The default value isfalse
.- When strict match is disabled (set to
false
), only the property values specified in<body>
are checked to be the same as the corresponding values in the request body. - If strict match is set to
true
, the full<body>
contents and the request body are checked to be exactly the same.
- When strict match is disabled (set to
-
field
is a JsonPath expression for a specific request body property. If provided, only this property is matched rather than the whole request body.
<mockData>
<query method="POST">https://httpbin.org/post</query>
<body>
{
"foo": "bar"
}
</body>
<!-- ... -->
</mockData>
Response
<response>
contains the response returned by the mock object as the response from the server.
This element is required. The element body contains the raw response.
$http.query
return value contains the HTTP response in the data
property as well as a number of extra fields like isOk
, status
, and others.
Do not add these extra properties in <response>
. Only the HTTP response from data
is needed.The tag supports the following attributes:
status
is the HTTP status code,200
by default.type
is the response type,json
by default.- If the response type is
json
orxml
, the response is parsed and returned to the script as a JS object. - Otherwise the response is returned as a string.
- If the response type is
<response>
body format and the type provided will cause a syntax error when the bot is deployed.<mockData>
<query>https://httpbin.org/json</query>
<response>
{
"slideshow": {
"title": "Sample Slide Show"
}
}
</response>
</mockData>
Response as a string
When the response type is neither json
nor xml
, the response is returned to the script as a string including all whitespace characters.
The responses from the following examples will be different:
- No whitespace
- With whitespace
<mockData>
<query>https://httpbin.org/get</query>
<response type="text">ok</response>
</mockData>
$http.query("http://httpbin.org/get"); // => {..., data: "ok"}
<mockData>
<query>https://httpbin.org/get</query>
<response type="text">
ok
</response>
</mockData>
$http.query("http://httpbin.org/get"); // => {..., data: "\n ok\n "}
Empty response
<response>
can be an empty element. In that case, the mock HTTP response returned to the script is an empty object.
<mockData>
<query>https://httpbin.org/status/204</query>
<response status="204"/>
</mockData>
Frequently asked questions
Where should I put mock objects?
<mockData>
elements can be placed in either <test>
or <test-case>
elements.
- Mock objects within
<test>
are available to all test cases belonging to this test. This is useful when the test cases verify some common piece of functionality. - Mock objects within
<test-case>
are only used for running this particular test case. They are unavailable to other test cases.
What order should mock objects be in?
- Mock objects within
<test>
can be placed anywhere after, before, or between test cases. - Mock objects within
<test-case>
should precede the<q>
elements which emulate queries triggering HTTP requests.
How many mock objects should there be?
Every test case should have as many mock objects as there are HTTP requests made when the test case is run.
Can I check different responses to the same HTTP request?
You can check the same HTTP request returning different responses throughout one test case.
Every <q>
tag triggering a request should have a corresponding mock object.
If several matching <mockData>
elements precede <q>
,
only the response from the last one will be used. Other mock objects will be ignored.
The example below illustrates this:
state: ExternalCall
q!: test
script:
$temp.res = $http.get("https://httpbin.org/get");
a: {{$temp.res.data}}
<test-case>
<!-- This mock object is ignored -->
<mockData>
<query>https://httpbin.org/get</query>
<response type="text">1</response>
</mockData>
<!-- This mock object is used for both requests made below -->
<mockData>
<query>https://httpbin.org/get</query>
<response type="text">2</response>
</mockData>
<q>test</q>
<a>2</a>
<q>test</q>
<a>2</a>
<!-- This mock object is only used for the request made below -->
<mockData>
<query>https://httpbin.org/get</query>
<response type="text">3</response>
</mockData>
<q>test</q>
<a>3</a>
</test-case>
How to use
Mocking query parameters
The example below is adapted from the tutorial on creating a bot with API requests. It contains a mock object for testing the state where the bot reports the current weather.
<test>
<mockData>
<query>http://api.openweathermap.org/data/2.5/weather?appid=${appid}&units=${units}&lang=${lang}&q=${q}</query>
<parameters>
<appid>***</appid> <!-- Replace the placeholder with your API key -->
<units>metric</units>
<lang>en</lang>
<q>London</q>
</parameters>
<response>
{
"weather": [
{
"main": "Clear",
"description": "clear sky"
}
],
"main": {
"temp": 9.82
}
}
</response>
</mockData>
<test-case>
<q>/start</q>
<a>Hello! I’m your virtual assistant. I can tell you the current weather in any city. Just tell me the city.</a>
<q>London</q>
<a>Today in London: clear sky, 10 °C.</a>
</test-case>
</test>
Mocking the request body
The following example illustrates different ways how the request body can be matched against the contents of <body>
.
state: ExternalCall
q!: test
script:
$temp.res = $http.post("https://httpbin.org/post", {
body: {
bodyParam1: "text1",
bodyParam2: "text2",
bodyObject: {
bodyParam3: 100,
bodyParam4: false
}
}
});
a: {{$temp.res.data}}
<test>
<!-- The actual request body exactly matches the expected one. -->
<test-case>
<mockData>
<query method="POST">https://httpbin.org/post</query>
<body strictMatch="true">
{
"bodyParam1": "text1",
"bodyParam2": "text2",
"bodyObject": {
"bodyParam3": 100,
"bodyParam4": false
}
}
</body>
<response type="text">ok 1</response>
</mockData>
<q>test</q>
<a>ok 1</a>
</test-case>
<!-- The values specified in <body> match the ones passed in the request. -->
<!-- A full match is not required because the `strictMatch` attribute is not set. -->
<test-case>
<mockData>
<query method="POST">https://httpbin.org/post</query>
<body>
{
"bodyParam1": "text1",
"bodyParam2": "text2"
}
</body>
<response type="text">ok 2</response>
</mockData>
<q>test</q>
<a>ok 2</a>
</test-case>
<!-- The object in `<body>` is matched against the `bodyObject` property in the request body. -->
<test-case>
<mockData>
<query method="POST">https://httpbin.org/post</query>
<body field="bodyObject">
{
"bodyParam3": 100,
"bodyParam4": false
}
</body>
<response type="text">ok 3</response>
</mockData>
<q>test</q>
<a>ok 3</a>
</test-case>
<!-- Here, the last mock object requires a full match against the `bodyObject` property. -->
<!-- Since the actual request body does not meet this condition, this mock object is ignored. -->
<!-- The preceding mock object is used instead. -->
<test-case>
<mockData>
<query method="POST">https://httpbin.org/post</query>
<body field="bodyObject">
{
"bodyParam3": 100
}
</body>
<response type="text">ok 4</response>
</mockData>
<mockData>
<query method="POST">https://httpbin.org/post</query>
<body field="bodyObject" strictMatch="true">
{
"bodyParam3": 100
}
</body>
<response type="text">would not match</response>
</mockData>
<q>test</q>
<a>ok 4</a>
</test-case>
<!-- If no `<body>` is provided, only the URL and request method are used for matching. -->
<test-case>
<mockData>
<query method="POST">https://httpbin.org/post</query>
<response type="text">ok 5</response>
</mockData>
<q>test</q>
<a>ok 5</a>
</test-case>
<!-- The mock object body can be a JSON primitive as well as an object. -->
<test-case>
<mockData>
<query method="POST">https://httpbin.org/post</query>
<body field="bodyParam2">"text2"</body>
<response type="text">ok 6</response>
</mockData>
<q>test</q>
<a>ok 6</a>
</test-case>
</test>