tests 模块介绍
tests 功能即断言验证结果。没有断言的测试是没有灵魂的。postman 的 tests 模块运行是基于 node.js 的,所以在 tests 模块下编写的代码也是使用 js 的方式编写,postman 断言的方式是通过基于 chai 的单元测试框架,可以确保您的 API 能够按预期运行,确定服务之间的集成可靠运行,并验证新开发未破坏任何现有功能。
tests 中的断言发生在请求之后,与 pre-request script 中的功能恰恰相反。当我们点击 send 之后,request 得到响应才会去执行 tests 模块的代码。
tests 功能应用
tests 执行顺序
在 postman 中,断言可以写在 collection ,folder,或者 request 里面。
针对整个 collection 里面的请求,那么请求的顺序如下:
- 先执行 collection 里面的 pre-request Script
- 再执行 folder 里面的 pre-request Script
- 最后执行 request 里面的 pre-request Script
- 请求完成之后,先执行 collection 里面的 test
- 再执行 folder 里面的 test
- 最终执行 request 里面的 test
验证结果查看
我们通过在 tests 模块下编写的断言,运行之后就可以在 test result 模块下查看断言的结果。
如果断言失败,也可以在 consle log 下查看失败的原因。
tests 断言规范
这里说明一下,在过去的版本中,可能还有很多小伙伴使用的断言方式是这样的,例如断言一个响应体里面是否包含 user_id :
tests["Body contains user_id"] = responsebody.has("user_id");
在新版本中,postman 官方已经不推荐使用这种方式断言。
新的断言方式应该是这样的,在
pm.test 的函数下包含 pm.expect 的断言:
pm.test("Status code is 200", () => {
pm.expect(pm.response.code).to.eql(200);
});
当然,这是官方不推荐,并不是说官方停止。目前来说,两种方式的断言还是可以用的。
tests 断言语法
对于 http/https 请求来说,现在很多公司都是使用 json 作为响应体,postman 不仅仅支持 json 的断言,还有包括 xml,html,csv 都可以进行断言,所有格式都会解析成 postman 认识的 js 内容。
# 响应体为 json
const responseJson = pm.response.json();
# 响应体为 xml
const responseJson = xml2Json(pm.response.text());
# 响应体为 html
const $ = cheerio.load(pm.response.text());
//output the html for testing
console.log($.html());
# 响应体为 csv
const parse = require('csv-parse/lib/sync');
const responseJson = parse(pm.response.text());
- 断言状态码
pm.test("Status code is 201", () => {
pm.response.to.have.status(201);
});
如果您想测试状态代码是否是一组中的一个,请将它们全部包含在一个数组中并使用oneOf
pm.test("Successful POST request", () => {
pm.expect(pm.response.code).to.be.oneOf([201,202]);
});
- 断言请求体
pm.test("Content-Type header is present", () => {
pm.response.to.have.header("Content-Type");
});
测试具有特定值的响应标头:
pm.test("Content-Type header is application/json", () => {
pm.expect(pm.response.headers.get('Content-Type')).to.eql('application/json');
});
- 断言响应体
pm.test("Person is Jane", () => {
const responseJson = pm.response.json();
pm.expect(responseJson.name).to.eql("Jane");
pm.expect(responseJson.age).to.eql(23);
});
- 断言响应时间
pm.test("Response time is less than 200ms", () => {
pm.expect(pm.response.responseTime).to.be.below(200);
});
上面举部分例子说明断言的用法,具体更多断言语法可以查看 Chai 断言库文档
常见断言事例
- 断言响应值的类型
根据响应体返回的 value 的类型进行断言,检查返回的类型是否符合我们的期待类型。当然这部分需要跟 api 文档描述的一致。
/* response has this structure:
{
"name": "Postman",
"age": 18,
"hobbies": [
"skating",
"painting"
],
"email": null
}
*/
const jsonData = pm.response.json();
pm.test("Test data type of the response", () => {
pm.expect(jsonData).to.be.an("object");
pm.expect(jsonData.name).to.be.a("string");
pm.expect(jsonData.age).to.be.a("number");
pm.expect(jsonData.hobbies).to.be.an("array");
pm.expect(jsonData.website).to.be.undefined;
pm.expect(jsonData.email).to.be.null;
});
- 断言数组属性
检查数组是否为空,以及它是否包含特定值:
/*
response has this structure:
{
"errors": [],
"areas": [ "goods", "services" ],
"settings": [
{
"type": "notification",
"detail": [ "email", "sms" ]
},
{
"type": "visual",
"detail": [ "light", "large" ]
}
]
}
*/
const jsonData = pm.response.json();
pm.test("Test array properties", () => {
//errors array is empty
pm.expect(jsonData.errors).to.be.empty;
//areas includes "goods"
pm.expect(jsonData.areas).to.include("goods");
//get the notification settings object
const notificationSettings = jsonData.settings.find
(m => m.type === "notification");
pm.expect(notificationSettings)
.to.be.an("object", "Could not find the setting");
//detail array must include "sms"
pm.expect(notificationSettings.detail).to.include("sms");
//detail array must include all listed
pm.expect(notificationSettings.detail)
.to.have.members(["email", "sms"]);
});
- 断言对象属性
pm.expect({a: 1, b: 2}).to.have.all.keys('a', 'b');
pm.expect({a: 1, b: 2}).to.have.any.keys('a', 'b');
pm.expect({a: 1, b: 2}).to.not.have.any.keys('c', 'd');
pm.expect({a: 1}).to.have.property('a');
pm.expect({a: 1, b: 2}).to.be.an('object')
.that.has.all.keys('a', 'b');
- 断言一个值在一个集合中
pm.test("Value is in valid list", () => {
pm.expect(pm.response.json().type)
.to.be.oneOf(["Subscriber", "Customer", "User"]);
});
- 断言包含一个对象
/*
response has the following structure:
{
"id": "d8893057-3e91-4cdd-a36f-a0af460b6373",
"created": true,
"errors": []
}
*/
pm.test("Object is contained", () => {
const expectedObject = {
"created": true,
"errors": []
};
pm.expect(pm.response.json()).to.deep.include(expectedObject);
});
验证响应结构
很多小伙伴应该遇到过一种情况,就是我希望可以验证响应的结构是否符合我期待的结构,而不是响应体里面的值。
postman 提供了两种方式对 json 的结构体进行验证
- 使用 Tiny Validator V4 (tv4) 执行 JSON 模式验证:
const schema = {
"items": {
"type": "boolean"
}
};
const data1 = [true, false];
const data2 = [true, 123];
pm.test('Schema is valid', function() {
pm.expect(tv4.validate(data1, schema)).to.be.true;
pm.expect(tv4.validate(data2, schema)).to.be.true;
});
- 使用 Ajv JSON 模式验证器验证 JSON 模式:
const schema = {
"properties": {
"alpha": {
"type": "boolean"
}
}
};
pm.test('Schema is valid', function() {
pm.response.to.have.jsonSchema(schema);
});
test setNextrequest()
可能在使用 postman 的过程中,有些小伙伴比较疑惑,如果我写了很多 request 了,但是在执行 collection 的时候,执行的顺序并不是我期待的那种,这样应该怎么解决呢? 在 postman 中,我们可以在 tests 模块下,编写我们需要执行下一步 request 的方法,告诉 postman 我们下一步应该执行哪一个接口。
postman.setNextRequest("request_name");
这样在执行完当前的接口时,postman 会执行下一个接口。request_name 指的是我们保存下来的 request 的名称。
总结
好了,这篇文章的内容就到这里了。希望可以帮助到大家对 postman 有更多的理解。