Adding Parameter Options and Dynamic Responses to Transactions
Service Virtualization Transactions in the Asset Catalog support the use of parameter options to allow for more dynamic, realistic response data. You can reference values in a Transaction request to ensure that they are repeated appropriately in the response body. For example, if your Transaction is requesting a name, you can configure the response to return a random name.
There are two important components to a creating dynamic responses:
- The parameters that control which data is returned, often based on request values
- Helpers that control the format of the returned data
To add dynamic responses to a Transaction, use the following functions:
- Import Transactions with Dynamic Responses from WireMock or RR pairs
- Add Dynamic Responses manually
- Supported Helper Functions
Import Transactions with Dynamic Responses
BlazeMeter supports preserving dynamic data from imported WireMock Transactions. WireMock uses Handlebar helper functions to dynamically generate responses, and BlazeMeter supports those functions. WireMock uses {{...}}
notation, while BlazeMeter uses ${...}
notation; however, BlazeMeter automatically adjusts the WireMock notation during import.
BlazeMeter also supports dynamic responses from imported RR pairs, as long as they use the supported ${...} notation.
For other source formats, like HAR, Swagger, and WSDL, import with dynamic responses data is not supported.
Add Dynamic Responses to a Transaction
When you add dynamic responses to an imported or manually created Transaction, you enrich the response data with information from the request. The referenced information can be either in a query parameter, the request header, a request cookie, or the request body.
Follow these steps:
- Open a Transaction in the Asset Catalog.
- Examine the Request data for potential values you want to parameterize and return in the response.
- Edit the Response Body to reference these values.
All dynamic responses must be contained within${...}
notation. For more information, see Dynamic Response Examples.
If you want to see a static response with a dollar curly bracket symbol (like${XYZ}
), use the backslash as an escape symbol in the response. For example, if you want to display the response${xyz}
at runtime, use the syntax\${xyz}
in the Transaction's response body. -
To return values in the response based on request data, use one of the following helpers:
request.query.<parametername>
Returns the value of the specified query parameter.request.headers.<headername>
Returns the value of the specified header. Within the response header, we are only evaluating the Value section. The Name in the header is not part of the dynamic response.request.cookies.<cookieid>
Returns the value of the specified cookie.request.body
Returns the full request body.
Other helpers are available to configure formatting, conditional responses, numeric data, and more. For a list of all available Helpers, see Supported Helper Functions.
- Save the Transaction.
You can give certain parameters random values, while others can return an exact value from the request. For example, if a request is asking to create a user account, you can configure the response to return the requested data in the response.
Dynamic Response Examples
Here are a few simple examples of dynamic response usage:
Return Request Query Parameter Values
Consider a marketing system with lead information. You want to return records matching a specific type of lead.
This Transaction looks up leads with a status of HOT:
http://localhost:64755/leads?status=HOT
The following Transaction response configuration will return response information with the desired status:
This configuration sets the status value to whatever you specify in the Transaction. Using this configuration, the original Transaction returns the following data:
Return Request Header Values
This example uses the Accept request header to send either a JSON or XML response based on the response time:
${#assign "mediaType"}${request.headers.Accept}${/assign} ${#eq mediaType 'application/json'} { "users":[ { "id":1, "name":"Mario Speedwagon", "status":"${request.query.status}" }, { "id":2, "name":"Petey Cruiser", "status":"${request.query.status}" }, { "id":3, "name":"Anna Sthesia", "status":"${request.query.status}" } ] } ${/eq} ${#eq mediaType 'application/xml'} <?xml version="1.0" encoding="UTF-8"?> <root> <users> <id>1</id> <name>Mario Speedwagon</name> <status>${request.query.status}</status> </users> <users> <id>2</id> <name>Petey Cruiser</name> <status>${request.query.status}</status> </users> <users> <id>3</id> <name>Anna Sthesia</name> <status>${request.query.status}</status> </users> </root> ${/eq}
Consider the following example Transaction:
https://mockservicejan3130547pm839-8080-default.mock-new.blazemeter.com/leads?status=HOT
With the dynamic response data entered into the Transaction, it will return a value of HOT for the status and return the data in XML or JSON depending on the Accept header value in the request.
Here is the response to the example Transaction with an application/xml Accept header value:
<?xml version="1.0" encoding="UTF-8"?> <root> <users> <id>1</id> <name>Mario Speedwagon</name> <status>HOT</status> </users> <users> <id>2</id> <name>Petey Cruiser</name> <status>HOT</status> </users> <users> <id>3</id> <name>Anna Sthesia</name> <status>HOT</status> </users> </root>
Here is the response to the example Transaction with an application/json Accept header value:
{ "users":[ { "id":1, "name":"Mario Speedwagon", "status":"HOT" }, { "id":2, "name":"Petey Cruiser", "status":"HOT" }, { "id":3, "name":"Anna Sthesia", "status":"HOT" } ] }
User Name Lookup - GET Request
This Transaction looks up a user name based on an ID number:
curl -X GET "https://contactapp.example.io/contact/1567" -H "accept: application/json"
While you may have recorded a few responses, you might also want a Transaction that returns realistic data when the other Transactions with recorded data are not matched.
The Request URL in BlazeMeter would look like this:
/contact/.*
To return a realistic ID and name value in the response, you would add the following to the Response Body:
The request.path
entry tells the response to use the first value in the request path as the value for the id parameter.
For the firstName parameter, the dynamic response creates a random alphabetic value of ten characters.
Account Creation - POST Request
This Transaction creates an account using a POST request with the required account data:
curl -X POST "https://contactapp.example.io/contact" -H "accept: application/json" -H "Content-Type: application/x-www-form-urlencoded" -d "firstName=John&lastName=Doe&phone=(999)-999-9999"
You want the response to return the requested data in the following format:
{
"id" : 3461,
"firstName" : "John" //The first letter should be capital
"lastName" : "DOE" //The whole string should be in upper case
"phone" : "(XXX)-XX-9999" // Only the last 4 digits needs to be visible
}
Here is how you would format the Transaction response body:
The inputForm argument specifically references the parameters from the request. Each of the three parameters also includes a helper that puts the output in the desired format.
Supported Helper Functions
Helpers let you control the format, appearance, and other factors related to the output date of a dynamic response. BlazeMeter supports the following helpers:
Request Helpers
Name |
Description |
Example |
---|---|---|
request.query.<key> |
Returns the value of the query parameter with the specified key |
${request.query.status} Returns the value of “status” query parameter. Example: http://localhost:80/test?status=InProgress |
request.headers.<key> |
Returns the value of the request header with the specified key. |
${request.header.Accept} Returns the value of the request header “Accept” . Example: |
request.cookies.<key> |
Returns the value of the cookie with the specified key. |
${request.cookies.JSESSIONID} Returns the value of the request header “JSESSIONID” . Example: http://localhost:80/test This request with the JSESSIONID cookie value of 1A530637289A03B07199A44E8D531427 returns the following response:1A530637289A03B07199A44E8D531427 |
request.body |
Returns the value of the body. s |
${request.body} Example: Post Request http://localhost:80/test with a request body value of: This request returns the following response: |
String Helpers
Name |
Description |
Example |
Example Response |
---|---|---|---|
capitalizeFirst |
Capitalizes the first character of the value | ${capitalizeFirst "hello world"} | Hello world |
center | Centers the value in a field of a given width | ${center "hello world" size=19 pad="-"} | ----hello world---- |
cut | Removes all values of an argument from the given string | ${cut "hello world" "d"} | hello worl |
defaultlfEmpty | If value evaluates to False, uses the given default. Otherwise, uses the value | ${defaultlfEmpty "" "none"} | none |
join | Joins an array, iterator, or an iterable with a string | ${join "a" "b" "c" " // "} | a // b // c |
ljust | Left aligns the value in a field of a given width | ${ljust "Hello" size=10 pad=" "} | “Hello “ |
rjust | Right aligns the value in a field of a given width | ${rjust "Hello" size=10 pad=" "} | “ Hello” |
substring | Returns a new string that is a subsequence of this sequence. The subsequence starts with the char value at the specified index and ends with the char value at index end - 1 | ${substring "Hello World" 0 5} | Hello |
lower | Converts a string into all lowercase | ${lower "HEllo"} | hello |
upper | Converts a string into all uppercase | ${upper "hellO"} | HELLO |
slugify | Converts to lowercase, removes non-word characters (alphanumerics and underscores), and converts spaces to hyphens. Also strips leading and trailing whitespace | ${slugify "Hello World"} | hello-world |
stringFormat | Formats the variable according to the argument, a string formatting specifier | ${stringFormat "Hello %s" "world"} | Hello World |
stripTags | Strips all [X]HTML tags | ${stripTags "<html><body><dummy>hello world</dummy></body></html>"} | hello world |
capitalize | Capitalizes all the whitespace separated words in a String | ${ capitalize "hello world"} | Hello World |
abbreviate | Truncates a string if it is longer than the specified number of characters. Truncated strings end with a translatable ellipsis sequence ("..."). Argument: Number of characters to truncate to | ${abbreviate "Hello World" 8} | Hello... |
wordWrap | Wraps words at the specified line length. Argument: number of characters at which to wrap the text | ${wordWrap "Lorem ipsum dolor sit amet, consectetur adipiscing elit." 14} |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. |
replace | Replaces each substring of this string that matches the literal target sequence with the specified literal replacement sequence | ${ replace "Hello ..." "..." "world" } | Hello world |
yesno | Maps values that resolve to true, false, and (optionally) null, to the strings "yes", "no", and "maybe", or given custom strings | ${yesno true yes="Hello" no="world" maybe="none"} | Hello |
numberFormat |
Format parameters is one of:
|
${numberFormat .24 "percent"} | 24% |
Number Helpers
Name |
Description |
Example |
Example Response |
isEven |
Returns a value only if the first argument is even. Otherwise, return null |
${isEven 2 "Hello"} |
Hello |
isOdd |
Returns a value only if the first argument is odd. Otherwise, return null |
${isOdd 3 "World"} |
World |
stripes |
Returns a different value if the passed argument is odd or even |
${stripes 2 "Hello" "World"} |
Hello |
Conditional Helpers
Name |
Description |
Example |
Example Response |
eq |
Tests if two elements are equals |
${#eq request.path.0 "hello"} "Hello is in the path" ${else} "Hello is not in the path" ${/eq} |
Returns “Hello is in the path” if the first part of the request’s path is equal to “Hello”; else returns "Hello is not in the path" |
neq |
Tests if two elements are NOT equals |
${#neq request.path.0 "hello"} "Hello is not in the path" ${else} "Hello is in the path" ${/neq} |
Returns “Hello is in the path” if the first part of the request’s path is equal to “Hello”; else returns "Hello is not in the path" |
gt |
Tests if the first argument is greater than the second one |
${#gt request.path.0 "hi"} "hello is lexicographically greater than hi" ${else} "Hello is not lexicographically greater than hi" ${/gt} |
Returns “hello is lexicographically greater than hi” if the first part of the request’s path is lexicographically greater than “hi”; else returns “Hello is not lexicographically greater than hi" |
gte |
Tests if the first argument is greater than or equal to the second one |
${#gt request.path.0 "hi"} "hello is lexicographically greater than hi" ${else} "Hello is not lexicographically greater than hi" ${/gt} |
Returns “hello is lexicographically greater than hi” if the first part of the request’s path is lexicographically greater than or equal to “hi”; else returns “Hello is not lexicographically greater than hi" |
lt |
Tests if the first argument is less than the second one |
${#lt request.path.0 "hi"} "hello is lexicographically lesser than hi" ${else} "Hello is not lexicographically lesser than hi" ${/lt} |
Returns “hello is lexicographically lesser than hi” if the first part of the request’s path is lexicographically lesser than “hi”; else returns “Hello is not lexicographically lesser than hi" |
lte |
Tests if the first argument is less than or equal to the second one |
${#lte request.path.0 "hi"} "hello is lexicographically lesser than hi" ${else} "Hello is not lexicographically lesser than hi" ${/lte} |
Returns “hello is lexicographically lesser than hi” if the first part of the request’s path is lexicographically lesser than or equal to “hi”; else returns “Hello is not lexicographically lesser than hi" |
and |
Truth of arguments is determined by isEmpty(), so this helper can be used with non-boolean values. Multiple values can also be specified |
${#and true "NonEmptyString" 10 request.path.0} Yes ${else} No ${/and} |
Returns “Yes”, as all the arguments evaluate to true |
or |
Truth of arguments is determined by isEmpty(), so this helper can be used with non-boolean values. Multiple values can also be specified |
${#or false "NonEmptyString"} Yes ${else} No ${/or} |
Returns “Yes”, as the second arguments evaluate to true |
not |
Truth of arguments is determined by isEmpty(), so this helper can be used with non-boolean values |
${#not false} Yes ${else} No ${/not} |
Yes |
Assign Helpers
Name | Description | Example | Example Response |
assign | Creates auxiliary variables |
${#assign "title"}Hello World${/assign} ${title} |
Hello World |
WireMock Helpers
BlazeMeter supports WireMock helpers to support import from open source. By default, these helpers use {{...}} in WireMock. BlazeMeter automatically fixes imported Transactions to use the supported ${...} notation, but if you are manually adding these to a Transaction, use the proper BlazeMeter supported notation for them to work.
BlazeMeter supports the following WireMock helpers:
- xPath
- soapXPath
- jsonPath
- randomValue
- hostname
- date
- now
- parseDate
- trim
- base64
- urlEncode
- formData
- regexExtract
- size
For more information about these helpers, see wiremock.org/docs/response-templating.
Response Helper
Name | Description | Example | Example Response |
response.body |
Returns the value that is specified in the Transaction→Response→Body field. Use this helper anywhere in the transactions, including HTTP calls and Wehbook calls. |
Transaction → Response → Body contains |
During execution, name=$(config.myName} resolves to name=John . |