Pandaria just abstracts DSL for API testing, after all it's still just cucumber steps
This page demonstrates the usage of the DSLs
You must configure some basics to make the framework work properly.
In order to be able to use files locates relate to the feature file, you must use dir
to specify
the directory of the current feature file, best practice is put it in the Background
section.
If you have below directory structure.
resources
└── features
└── http
├── http.feature
└── requests
└── user.json
You can use the json file as request body as below
Feature: Http feature
Basic http operations with verifications
Background:
* dir: features/http
Scenario: simple post with jsn
* uri: http://localhost:10080/users
* request body: requests/user.json
* send: POST
* status: 200
* verify: '$.id'='auto-generated'
* verify: '$.username'='jakim'
* verify: '$.age'=18
dir
supports relative path and absolute path(relative to classpath)
Background:
* dir: features/http
Scenario: simple post with jsn
* uri: http://localhost:10080/users
* request body: requests/user.json
* request body: classpath:user.json
In order to shorten the uri and reduce the duplication, you can configure a base uri
and then use relative uri when
sending requests.
Feature: Http feature
Basic http operations with verifications
Background:
* dir: features/http
* base uri: http://localhost:10080
Scenario: simple get
* uri: /users/me
* send: GET
* status: 200
* verify: '$.username'='jakim'
* verify: '$.age'=18
You can use absolute uri with uri: http://host:port
, best practice is to make it short
Java faker is used in pandaria to generate fake testing data, by default the locale is "en", you can set the default locale
in application.properties, you can override the locale use faker locale
like below.
Scenario: faker locale
* faker locale: zh-CN
* var: name=faker: #{name.full_name}
* verify: ${name} matches: '\p{sc=Han}*'
* uri: http://localhost:10080/users/me
* send: GET
* status: 200
* verify: '$.username'='jakim'
* verify: '$.age'=18
* uri: http://localhost:10080/users
* request body:
"""
{"username": "jakim", "age": 18}
"""
* send: POST
* status: 200
* verify: '$.id'='auto-generated'
* verify: '$.username'='jakim'
* verify: '$.age'=18
Scenario: get with http header
* uri: /custom_header
* header: 'Accept'='text.plain'
* send: GET
* status: 200
* response body:
"""
success
"""
Scenario: simple put
* uri: /users/me
* request body:
"""
{"username": "lj"}
"""
* send: PUT
* status: 200
* verify: '$.username'='lj'
Scenario: simple delete
* uri: /users/20
* send: DELETE
* status: 200
Scenario: simple patch
* uri: /users/20
* request body:
"""
{"username": "lj"}
"""
* send: PATCH
Scenario: simple head
* uri: /users
* send: HEAD
* status: 200
* response header: 'test'='first,second,third'
* response header: 'Date'='Thur, 2018 12'
Scenario: simple options
* uri: /users
* send: OPTIONS
* status: 200
* response header: 'Allow'='OPTIONS, GET, HEAD'
Scenario: simple trace
* uri: /users
* send: TRACE
* status: 200
* response header: 'Content-Type'='message/http'
* uri: /users?name=jakim&age=18
* uri: /users
* query parameter: 'name'="${name}"
* query parameter: 'age'='18'
* uri: /users?name=jakim
* query parameter: 'age'='18'
If your query parameter has special charaters which need to be encoded, please use query parameter
* uri: /users
* query parameter: 'name'='jakim li'
* send: GET
* uri: /custom_header
* header: 'Accept'='text.plain'
* header: 'Content-Type'='text/plain'
* send: GET
* status: 200
The default content type is application/json, you can override it by setting a Content-Type
header
It's useful to have a http header that can be applied to every http request, for testing account authentication.
global header can be used in this way. Put below in your application.properties
:
application.properties
http.headers.Authorization=Bear Token
http.headers.global=globalHeader
http.headers.will_be_overrided=not_overrided
Every http request will automatically apply these headers.
Global headers can be overrided use header
keyword.
You can add cookie(s) to request
@http
Feature: Http feature
Basic http operations with verifications
Background:
* dir: features/http
* base uri: http://localhost:10080
Scenario: add cookie
* uri: /cookie
* cookie: 'key'='value'
* send: get
* response body:
"""
cookie added
"""
* uri: /cookie
* var: val="value"
* cookie: 'key'="${val}"
* send: get
* response body:
"""
cookie added
"""
The request body can either come from a file or you write it directly as docstring in feature file.
* uri: http://localhost:10080/users
* request body: requests/user.json
* send: POST
* status: 200
* verify: '$.id'='auto-generated'
* verify: '$.username'='jakim'
* verify: '$.age'=18
Scenario: simple put
* uri: /users/me
* request body:
"""
{"username": "lj"}
"""
* send: PUT
* status: 200
* verify: '$.username'='lj'
The convention is the string right after * request body:
is path to the file, docstring is directly the request body
* request body: path_to_file
* request body:
"""
request body from docstring
"""
You can upload file as attachment
@file_upload
Feature: file upload
be able to upload file
Background:
* dir: features/http
* base uri: http://localhost:10080
Scenario: upload file
* uri: /files
* attachment: attachments/abc.txt
* send: POST
* status: 200
* response body:
"""
uploaded
"""
If you have attachment, request body(if have) will be ignored
Multiple attachments are allowed.
@since 0.3.2
You can submit form with attachments
Scenario: upload file with form data
* form: /form
* field: name value:
"""
lj
"""
* field: data value:
"""
{"name": "lj", "age", 18}
"""
* field: user value: requests/user.json
* field: file attachment: attachments/abc.txt
* send: POST
* status: 200
* response body:
"""
uploaded
"""
attachment
outside of the field
will also work, the field name will be default to filename.
In most test environment, self-signed certificates are used for HTTPS, pandaria DOES NOT do host verification by
default. But you can enable it by put below configuration in your application.properties
http.ssl.verify=true
If you enable the host verification, you MUST specify the certificates information based on standardized system properties for SSL configuration.
Java system properties are used for HTTP(S) proxy. e.g, below is how to add it using gradle
./gradlew -Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=8088 build
@since 0.3.0
Pandaria support graphql testing over HTTP, currenty query and mutation are supported.
Unlike REST, Graphql only needs a single endpoint, so you can just set the base url like below:
Background:
* dir: features/graphql
* base uri: http://localhost:10081/graphql
Scenario: basic query without specify operation name
* graphql:
"""
query bookById($id: String){
book(id: $id) {
title
isbn
author {
name
}
}
}
"""
* variables:
"""
{
"id": "1"
}
"""
* send
* verify: '$.data.book.title'='CSS Designer Guide'
* verify: '$.data.book.isbn'='ISBN01123'
* verify: '$.data.book.author.name'='someone'
You can send a graphql query and verify the returning data. variables are optional.
Or you can put the query and variables in file as usual.
* graphql: query_book_by_id.graphql
* variables: css_designer_guide.id.json
* send
* verify: '$.data.book.title'='CSS Designer Guide'
* verify: '$.data.book.isbn'='ISBN01123'
* verify: '$.data.book.author.name'='someone'
Usage of mutation similar with query, just replace the query with mutation.
Variable is optional.
* variables:
"""
{
"id": "1"
}
* variables: css_designer_guide.id.json
If multiple operations presented in one single request, operation name is required by graphql server. it's optional when single operation presented in single request.
Scenario: query with operation name
* graphql: query_book_by_id.graphql
* variables: css_designer_guide.id.json
* operation: bookById
* send
* verify: '$.data.book.title'='CSS Designer Guide'
* verify: '$.data.book.isbn'='ISBN01123'
* verify: '$.data.book.author.name'='someone'
You can directly use sql to operate on database, pandaria use spring jdbc, you need to configure your datasource
in application.properties
like below
spring.datasource.url=jdbc:mysql://localhost:3307/pandaria?useSSL=false&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
You can write sql with select statements to query database and verify the results using the json path.
The results of select will always be array, keep it in mind when using json path
Feature: database
database related operations
Background:
* dir: features/database
Scenario: execute sql and query
* execute sql:
"""
DROP TABLE IF EXISTS USERS;
CREATE TABLE USERS(
NAME VARCHAR(256) NOT NULL,
AGE INTEGER(5) NOT NULL
);
INSERT INTO USERS(NAME, AGE) VALUES('jakim', 18);
"""
* query:
"""
SELECT NAME, AGE FROM USERS
"""
* verify: '$[0].name'='jakim'
* verify: '$[0].age'=18
Scenario: sql from file
* execute sql: drop_table.sql
* execute sql: setup.sql
* query: select.sql
* verify: '$[0].name'='jakim'
* verify: '$[0].age'=18
* execute sql:
"""
DROP TABLE IF EXISTS USERS;
CREATE TABLE USERS(
NAME VARCHAR(256) NOT NULL,
AGE INTEGER(5) NOT NULL
);
"""
* execute sql: drop_table.sql
* execute sql: setup.sql
@since 0.3.4
You can specify additional data source and specify which one to use while executing sql or query from database.
First in your application.properties
, add your data source configuration.
spring.datasource.url=jdbc:mysql://localhost:3306/pandaria?useSSL=false&allowMultiQueries=true&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.additional[0].url=jdbc:mysql://localhost:3317/pandaria?useSSL=false&allowMultiQueries=true&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
spring.datasource.additional[0].name=foo
spring.datasource.additional[0].username=root
spring.datasource.additional[0].password=
spring.datasource.additional[0].driver-class-name=com.mysql.jdbc.Driver
spring.datasource.additional[1].url=jdbc:mysql://localhost:3318/pandaria?useSSL=false&allowMultiQueries=true&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
spring.datasource.additional[1].name=bar
spring.datasource.additional[1].username=root
spring.datasource.additional[1].password=
spring.datasource.additional[1].driver-class-name=com.mysql.jdbc.Driver
Above configures 3 datasources, the first one will be referenced as default
, others will be referenced by their name.
default
is a reserved data source name, specify an additional data source named as default
cause error.
Then you can specify which database your sql or query be executed against to:
* db: foo execute sql: setup_foo.sql
* db: foo query: query_foo.sql
* verify: '$[0].name'='jakim'
* verify: '$[0].age'=18
* db: bar execute sql: setup_bar.sql
* db: bar query: query_bar.sql
* verify: '$[0].name'='jakim'
* verify: '$[0].age'=18
execute sql
or query
without specify db will be executed against to default
data source. same as:
* db: default sql: setup_foo.sql
@since 0.2.0
@since 0.2.0
Insert one document into a collection
* collection: 'users' insert:
"""
{"user": "jakim"}
"""
or put document in file
* collection: 'users' insert: document/alice.json
@since 0.2.0
Delete all documents in collection
* collection: 'users' clear
@since 0.2.0
Find all documents from collection, you can verify like verify in database, it's always an JSON array.
* collection: 'users' find all
* verify: '$[0].user'="alice"
@since 0.2.0
Instead of find all documents, you can filter the results.
* collection: 'users' clear
* collection: 'users' insert:
"""
{"user": "jakim", "age": 18}
"""
* collection: 'users' insert:
"""
{"user": "alice", "age": 16}
"""
* collection: 'users' find:
"""
{"age": {$gt: 17}}
"""
* verify: '$[0].user'="jakim"
* collection: 'users' find:
"""
{"age": {$lt: 17}}
"""
* verify: '$[0].user'="alice"
* collection: 'users' find: filter/greater_than_17.json
* verify: '$[0].user'="jakim"
@since 0.2.1
You can put initial value in application.properties
.
application.properties
variables.environment=test
Scenario: initial value from configuration file
* verify: ${environment}="test"
* var: environment="production"
* verify: ${environment}="production"
COMPATIBILITY WARNING:
If your version <= 0.2.4, you need to define variable with single quote around the name. such as var: 'three'=3
If you define variable use single quote, '${name}'
, variable will NOT be replaced.
Scenario: const string
* var: name='panda'
* verify: ${name}='panda'
If you define variable use double quote, "${name}"
, variable will be replaced.
Scenario: string
* var: name='panda'
* var: great="hello ${name}"
* verify: ${great}='hello panda'
* verify: ${great}="hello ${name}"
Scenario: integer
* var: age=18
* verify: ${age}=18
It's useful if we can extract values from response body as variables. you can do it using <-
like below.
var: name<-'json path'
will extract value from the http response body json using the json path and assign it to the variable with specified name
Scenario: from json
* uri: /not_important
* send: GET
* status: 200
* var: name<-'$.name'
* var: age<-'$.age'
* var: iq<-'$.iq'
* verify: ${name}='panda'
* verify: ${age}=18
* verify: ${iq}=double: 80.0
You can also extract from database query results
* query: select.sql
* var: age<-'$[0].age'
@since 0.2.7
You can extract a cookie and assign it to variable
Scenario: read response cookie value
* uri: /mock_login
* send: POST
* var: jsession<-cookie:'SessionId'
* verify: ${jsession}='ABCDEFG'
@since 0.2.8
* uri: /simple_response
* send: GET
* status: 200
* var: content<-response body
* verify: ${content}='SIMPLE_RESPONSE'
@since 0.2.1
You can evaluate javascript code and assign the result as a variable.
* var: three=3
* var: six=code:
"""
${three} + 3
"""
* verify: ${six}=6
* var: zero=code: ${three} - 3
* verify: ${zero}=0
* var: ten=code file: six_add_four.js
* verify: ${ten}=10
Scenario: variable being replaced in uri
* var: path="not_important"
* uri: /${path}
* send: GET
* status: 200
* verify: '$.name'='panda'
* verify: '$.age'=18
* verify: '$.iq'=double: 80.0
requsts/someone.json
{
"name": "${name}"
}
Scenario: variable used in request file
* var: name='someone'
* uri: /users
* request body: requests/someone.json
* send: POST
* status: 201
* response body:
"""
{"user":"${username}"}
"""
@since 0.3.1
* uri: /custom_header_value_from_variable
* var: value="some_value"
* header: 'SomeName'="${value}"
* send: GET
* status: 200
@since 0.2.1
* var: three=3
* var: six=code:
"""
${three} + 3
"""
You can escape the variables by place an extra $
* var: six=code:
"""
$${three} + 3
"""
This gives error because ${three}
is not understand by javascript engine.
@since 0.2.2
Its useful to have random real-looking fake data for testing, Pandaria has integerated with java-faker for fake data generation.
@since 0.2.2
You can generate fake data and assign it to a variable, #{expression}
is used.
* var: name=faker: #{Name.firstName}
* verify code: "${name}".length > 0
* var: full_name=faker: #{Name.fullName}
* verify code: "${full_name}".length > 0
@since 0.2.2
Or you can directly use it in request body, or sql, mongo json, works in file as well.
* uri: /faker/users
* request body:
"""
{"name": "#{Name.fullName}", "city": "#{Address.city}"}
"""
* send: POST
* response body:
"""
success
"""
@since 0.2.2
You can switch locale, default is en
.
* faker locale: zh-CN
* var: name=faker: #{Name.fullName}
* verify: ${name} matches: '\p{sc=Han}*'
* verify: ${name} matches: '\p{sc=Han}*'
ensure ${name}
all chinese characters.
@since 0.2.2
Default locale can be set in application.properties
with faker.locale
faker.locale=zh-CN
@since 0.2.2
You can escape it:
* uri: /faker/users/escape
* request body:
"""
{"name": "#{Name.fullName}", "city": "##{Address.city}"}
"""
* send: POST
* response body:
"""
success
"""
In above example, name will be set to a fake name, but city will be set to #{Address.ctiy}
You are not allowed to escape when define varaible use faker with fake data, var: name=faker: ##{Name.fullName}
will not work, use var: name='#{Name.fullName}'
instead.
@since 0.2.3
It's useful that you can use part of or whole http response as next request body. you can use @{<json path>}
in your
next request body, Pandaria will replace it for you. Works in file as well.
Whole response for next request
* uri: /users/me
* send: get
* verify: '$.username'='jakim'
* verify: '$.age'=18
* verify: '$.iq'=double: 80.0
* uri: /users
* request body:
"""
@{$}
"""
* send: POST
* status: 200
* verify: '$.id'='auto-generated'
* verify: '$.username'='jakim'
* verify: '$.age'=18
Part of the response for next request
* uri: /users/me
* send: get
* verify: '$.username'='jakim'
* verify: '$.age'=18
* verify: '$.iq'=double: 80.0
* uri: /users
* request body:
"""
{ "username": @{$.username}}
"""
* send: POST
* status: 200
* verify: '$.id'='auto-generated'
* verify: '$.username'='jakim'
* verify: '$.age'=18
Please be careful about the double quotes, because Pandaria assumes the value of json path expression is also a JSON,
so it will automatically handle double quotes, with variables in ${}
or faker expresson #{}
, you will need to handle
double quotes yourself
* uri: /empty_request
* send: POST
* status: 201
* uri: /users
* send: TRACE
* status: 200
* response header: 'Content-Type'='message/http'
verify use json path
* verify: '$.username'='jakim'
* verify: '$.age'=18
verify as text
* response body:
"""
success
"""
verify as text in file
* response body: responses/success.txt
Same with the request body, the convention is string right after * response body:
is the path to file. the text
in docstring in next line is dirctly the response body.
You can verify database tables by writing sql with select statements, and then verify the result.
For table
name | age |
---|---|
jakim | 18 |
panda | 28 |
in json array
[
{ "name": "jakim", "age": 18 },
{ "name": "panda", "age": 28 }
]
The query result will always be json array even if only one row in the result
Then just using the same as you verify json http response body
* query: select.sql
* verify: '$[0].name'='jakim'
* verify: '$[0].age'=18
Although you can use string verificaton to non-string types, it will be converted to its string format.
=
for equals, !=
for not equals
Scenario: equals
* uri: /users/me
* send: GET
* status: 200
* verify: '$.username'='jakim'
* var: kim="kim"
* var: user='jakim'
* verify: ${user}="ja${kim}"
* verify: '$.username'="jakim"
* verify: '$.username'="ja${kim}"
* var: age=18
* var: iq=80.0
* verify: ${user}!='notjakim'
* verify: ${user}!="notja${kim}"
* verify: ${age}!=19
* verify: ${iq}!=double: 89.0
* verify: ${age}!=${iq}
* verify: '$.username'!="notjakim"
* verify: '$.username'!="notja${kim}"
* verify: '$.age'!=19
* verify: '$.iq'!=double: 89.0
Scenario: contains
* uri: /users/me
* send: GET
* status: 200
* verify: '$.username'='jakim'
* verify: '$.username' contains: 'kim'
* var: username="panda"
* verify: ${username} contains: 'anda'
* verify: '$.username'='jakim'
* verify: '$.username' starts with: 'jak'
* var: username="jakim"
* verify: ${username} starts with: 'jak'
* var: prefix='jak'
* verify: '$.username' starts with: "${prefix}i"
* verify: ${username} starts with: "${prefix}i"
* verify: '$.username'='jakim'
* verify: '$.username' ends with: 'kim'
* var: username="jakim"
* verify: ${username} ends with: 'kim'
* var: suffix='kim'
* verify: '$.username' ends with: "ja${suffix}"
* verify: ${username} ends with: "ja${suffix}"
* verify: '$.username'='jakim'
* verify: '$.username' length: 5
* var: username="jakim"
* verify: ${username} length: 5
* var: abc=3
* verify: ${abc} length: 1
* verify: '$.username'='jakim'
* verify: '$.username' matches: '.*'
* var: username="jakim"
* verify: ${username} matches: 'j.*im'
* verify: '$.age'>17
* verify: '$.iq'>double: 70.0
* verify: '$.age'>=18
* verify: '$.iq'>=double: 80.0
* var: age=18
* var: iq=80.0
* verify: ${age}>17
* verify: ${iq}>double: 79.0
* verify: ${age}>=17
* verify: ${iq}>=double: 80.0
* verify: '$.age'<19
* verify: '$.iq'<double: 90.0
* verify: '$.age'<=18
* verify: '$.iq'<=double: 80.0
* var: age=18
* var: iq=80.0
* verify: ${age}<19
* verify: ${iq}<double: 99.0
* verify: ${age}<=18
* verify: ${iq}<=double: 80.0
Scenario: equals
* query:
"""
select `date`, `datetime`, `timestamp`, `time` from all_data_types;
"""
* verify: '$[0].date'=datetime: '2008-10-10' pattern: 'yyyy-MM-dd'
* verify: '$[0].date'=datetime: '10/10/2008+0800' pattern: 'dd/MM/yyyyZ'
* verify: '$[0].datetime'=datetime: '2008-08-08 10:30:30' pattern: 'yyyy-MM-dd hh:mm:ss'
* verify: '$[0].timestamp'=datetime: '2008-01-01 00:00:01' pattern: 'yyyy-MM-dd HH:mm:ss'
* verify: '$[0].time'=datetime: '10:30:10' pattern: 'hh:mm:ss'
Scenario: before
* query:
"""
select `date`, `datetime`, `timestamp`, `time` from all_data_types;
"""
* verify: '$[0].date' before: datetime: '2008-10-11' pattern: 'yyyy-MM-dd'
* verify: '$[0].date' before: datetime: '11/10/2008+0800' pattern: 'dd/MM/yyyyZ'
* verify: '$[0].datetime' before: datetime: '2008-08-08 10:30:31' pattern: 'yyyy-MM-dd hh:mm:ss'
* verify: '$[0].timestamp' before: datetime: '2008-01-01 00:00:02' pattern: 'yyyy-MM-dd HH:mm:ss'
* verify: '$[0].time' before: datetime: '10:30:11' pattern: 'hh:mm:ss'
Scenario: after
* query:
"""
select `date`, `datetime`, `timestamp`, `time` from all_data_types;
"""
* verify: '$[0].date' after: datetime: '2008-10-09' pattern: 'yyyy-MM-dd'
* verify: '$[0].date' after: datetime: '09/10/2008+0800' pattern: 'dd/MM/yyyyZ'
* verify: '$[0].datetime' after: datetime: '2008-08-08 10:30:29' pattern: 'yyyy-MM-dd hh:mm:ss'
* verify: '$[0].timestamp' after: datetime: '2008-01-01 00:00:00' pattern: 'yyyy-MM-dd HH:mm:ss'
* verify: '$[0].time' after: datetime: '10:30:09' pattern: 'hh:mm:ss'
- Allow different order in array
- NOT allow extra items in array
- NOT allow extra or missing object
* uri: /users/me
* send: get
* verify: '$' same json:
"""
{
"iq": 80.0,
"username": "jakim",
"age": 18
}
"""
* verify: '$' same json: responses/jakim.json
- Allow different order in array
- Allow extra item(s) in array
- Allow extra object(s)
- NOT allow missing fields
Scenario: contains json, extra fields allowed
* uri: /users/list
* send: get
* verify: '$' contains json:
"""
[
{
"name": "jakim"
},
{
"name": "smart", friends: ["sue"]
}
]
"""
* var: response<-'$'
* verify: '$' contains json:
"""
[
{
"name": "jakim"
},
{
"name": "smart", friends: ["sue"]
}
]
"""
If the json is an array, you can verify the size, if the returning json is an object, then the size verify the key set size.
Scenario: has size for array
* uri: /users/list
* send: get
* verify: '$' same json:
"""
[
{
"name": "jakim",
"friends": [
"james", "jack"
]
},
{
"name": "smart",
"friends": ["sue", "lucy"]
},
{
"name": "haha"
}
]
"""
* verify: '$' has size: 3
* verify: '$.size()'=3
JSON schema is useful to describe the API, and it's useful especially for contract testing. you can verify json document(instance) conforms to a given json schema or not.
@verify_json_schema
Feature: verify json schema
verify if json valid for json schema
Background:
* dir: features/verification
* base uri: http://localhost:10080
Scenario: verify json schema
* uri: /products/1
* send: get
* verify: '$' conform to:
"""
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/product.schema.json",
"title": "Product",
"description": "A product in the catalog",
"type": "object"
}
"""
* verify: '$' conform to: schema/product.schema.json
* verify: '$.tags' conform to:
"""
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/product.tags.schema.json",
"title": "product tags",
"description": "Product tags",
"type": "array",
"items": {
"type": "string"
}
}
"""
Scenario: null check
* uri: /users/me
* send: GET
* status: 200
* verify: '$.username'='jakim'
* verify: '$.username' is not null
* var: username="jakim"
* verify: ${username} is not null
* verify: ${hello} is null
* uri: /getnull
* send: GET
* status: 200
* verify: '$.notexist' is null
You can verify is response/result/variable equals/not-equals to a variable.
* verify: '$.username'=${user}
* verify: '$.username'!=${kim}
* verify: ${user}=${user}
* verify: ${user}!=${kim}
@since 0.3.2
* verify: '$[0]'=${first_user}
* verify: '$[0].name'=${first_user.name}
* verify: '$[0].friends'=${first_user.friends}
Currently nested variable reference is not supported in script, file and docstring yet. will be supported later.
@since 0.2.1
You can write javascript code snippet for verification, there are two forms, verify against the evaluation result or verify the evaluation result is true.
You can write the code snippet in one line, in block as doc string, or in separate file.
Things to note
- If you have multiple lines in the code snippet, only the result of the last line will be used as the result.
- If you need to write complex code in the snippet, consider to put them in java with cucumber steps first.
- Nashorn is used for script evaluation.
- If your jdk version under java 8u40, you might encounter issue about 0 was returned as 0.0, you can either upgrade your jdk version or you need to use it as double.
@since 0.2.1
* var: age=16
* var: iq=90.0
* uri: http://localhost:10080/not_important
* send: get
* verify: '$.age'=code: ${age} + 2
* verify: '$.iq'=code: ${iq} - 10
* verify: '$.age'!=code: ${age} + 3
* verify: '$.iq'!=code: ${iq} - 11
* verify: '$.age'=code:
"""
${age} + 2
"""
* verify: '$.iq'=code:
"""
${iq} - 10
"""
* verify: '$.age'=code file: 18.js
* verify: '$.iq'!=code file: 18.js
@since 0.2.1
Be notice the double equals ==
are used for comparison in javascript instead of single equal =
which was used in pandaria.
* verify code: ${name} == ${iq} / 3
* verify code:
"""
${name} != ${iq} % 3
"""
* verify code file: verification.js
It's impossible for pandaria to provide all the verificaitons, you can always write your own verifications. Here is a tutorial on how
Wait is useful for automation testing and sometimes is necessary.
Only support milliseconds and seconds, we don't recomment to wait for very long time.
Scenario: wait
* wait: 1000ms
* wait: 1s
Waiting is a time consuming step, sometimes make the tests slow, but it's necessary.
wait 1000ms times 3
specifies the framework to wait 3 times, each time wait 1000ms
Run this step DOSE NOT put the thread in sleep immediately. if the first coming verification failed, then it
actually put the thread in sleep for 1000ms
, and then retry once, and this process will repeat 3
times.
GET /sequence
returns plain text in sequence
server.server()
.get(by(uri("/sequence")))
.response(seq("1", "2", "3", "4", "5", "6", "7", "8", "9", "10"));
Wait until:
Scenario: wait until
* wait: 1000ms times: 3
* uri: /sequence
* send: GET
* response body:
"""
3
"""
* uri: /sequence
* send: GET
* response body:
"""
4
"""
* wait: 1s times: 3
* uri: /sequence
* send: GET
* response body:
"""
5
"""
* uri: /sequence
* send: GET
* response body:
"""
6
"""
* wait: 1000ms times: 3
* query:
"""
SELECT NAME, AGE FROM USERS;
"""
* verify: '$[0].name'="jakim"
* verify: '$[0].age'=18
Although between wait and the first verificaiton, there can be multiple actions(http request or database queries), all actions between will be take as retry, but only the last action can be verified. For example:
* wait: 1000ms times: 3
* uri: /sequence
* send: GET
# no verifiction for this http request
* query:
"""
SELECT NAME, AGE FROM USERS;
"""
* verify: '$[0].name'="jakim"
* verify: '$[0].age'=18
Both the database query and the http request will be repeated, but verification can only be applied to the database query
You use utitlities by assign them as variable and use it.
Scenario: generate random number
* var: uuid=random uuid
* verify: ${uuid} length: 36
Example uuid: 123e4567-e89b-12d3-a456-556642440000
You can generate almost all kinds of random testing data by using faker expression
@since 0.3.5
You can print something for debugging purpose
* print: "begin"
* print: "@{$}"
* print: "@{$.username}"
* print: "<string>"
* print: "${var_id}"
* print: '${var_id}'
* print: "end"
You can use cucumber senario outline for data driven scenarios
@outline
Feature: data driven
data driven should work with scenario outline
Background:
* dir: features/outline
* base uri: http://localhost:10080
Scenario Outline:
* uri: /users
* request body:
"""
{ "username": "<username>" }
"""
* send: POST
* status: 200
* verify: '$.username'='<username>'
Examples:
| username |
| jakim |
| alice |
| bob |
| steve |
Use variable, so you can reference data in Examples section in external file.
Scenario Outline:
* var: username='<username>'
* uri: /users
* request body: requests/user.json
* send: POST
* status: 200
* verify: '$.username'='<username>'
Examples:
| username |
| jakim |
| alice |
| bob |
| steve |
requests/user.json
{
"username": "${username}"
}