手把手教会你做API自动化测试,你需要有一点点扣腚经验,至少保证能准确的ctrl+c & ctrl+v
API自动化是一个低投入高产出的工作,几乎适用于所有的api项目。
完整的自动化测试解决方案需要包含 环境构筑 自动化执行 环境清理 3个主要步骤,关于环境构筑不在本教程里覆盖,需要case by case来看合适的方案。
-
下载安装
-
命令行安装
npm install -g newman
npm install -g newman-reporter-htmlextra
- jsonserver(非必须,本教程用做API服务器的mock,用法很多,自行参考 )
npm install -g json-server
注:jsonserver最为rest服务的mock,可以低成本的解决很多问题,值得深入学习一下,欢迎一起探讨
-
本教程用到的相关软件的版本
- Postman v7.0.9
- Node v10.15.2
- npm v6.4.1
- newman v4.4.1
- json-server v0.14.2
找到一个空目录(参考sample目录),创建一个db.json的文件
{
"animals": [
]
}
启动模拟环境
json-server --watch db.json
本教程会通过下面2个API请求,覆盖大部分用法
- 通过post请求创建一个动物
- 通过get请求获取创建完的动物
自动化测试的执行需要3个主要输入文件
- 测试用例
- 测试数据
- 环境配置
本教程会教会你怎么创建并使用这3个文件
当然,报告也是必不可少的,如何生成报告也会在本教程中被覆盖
自动化测试只是把手工测试的步骤自动化执行,so第一步,我们先来手工做一遍
{
"name": "first animal",
"type": "cat",
"age": 2,
"likes": [
"fish", "mouse"
]
}
结果如下图,返回201,表示正常,创建完的数据也加上了id并放回
光发送请求是不够的,我们在增加一些验证,先对我们要做的验证做一点描述
接下来增加验证的代码,验证我们用chai的assert模块 Tests框内的代码部分可以从下面黏贴,代码部分说明参考注释
// 引入chai的assert模块作为验证用模块
const chai = require('chai');
const assert = chai.assert;
// 验证返回值,通常返回值可能有200,201,202,本例中3返回值为这3个中的一个即为pass,实际使用中可以按需修改
pm.test("验证返回值201", function () {
pm.expect(pm.response.code).to.be.oneOf([200,201,202]);
});
// 验证返回值
pm.test("验证返回数据跟预想一致", function () {
// 获取返回值
const jsonData = pm.response.json();
// 设置预想值
const expectData = {
name: 'first animal',
type: 'cat',
age: 2,
likes: [
'fish', 'mouse'
]
};
// 为方便后期排查,我们把预想值和实际值转换成string类型
const actualstr = JSON.stringify(jsonData);
const expectstr = JSON.stringify(expectData);
// 比较预想值和实际值,当验证不通过事后输出参数3的字符串方便排查
// 本例用的json结果的比较,jsonData里只需要包含所有的expectData即为通过,其他验证类型参考文档
assert.deepInclude(jsonData, expectData, `acutal:${actualstr} | expect:${expectstr}`);
// id为自增字段,每一次请求都不一定相同,为了后面使用,把返回值的id保留到全局变量newid
pm.globals.set("newid", jsonData.id);
});
至此第一个请求完成,接下来我们补充全局变量的用法
参考post来再创建一个新的请求"通过get请求获取创建完的动物",此处不详细截图了,创建完如下
此处请求地址里用到了{{newid}},这个newid的值即为第一个post请求最后的Tests代码里设置的,创建完的id,此处通过get请求来get指定id的数据
Tests代码
const chai = require('chai');
const assert = chai.assert;
// 从全局变量里取得newid的值
const expectid = pm.globals.get("newid");
pm.test("验证返回值200", function () {
pm.expect(pm.response.code).to.be.oneOf([200,201,202]);
});
pm.test("验证返回数据跟预想一致", function () {
const jsonData = pm.response.json();
const expectData = {
// 加入对期待值的验证
id: expectid,
name: 'first animal',
type: 'cat',
age: 2,
likes: [
'fish', 'mouse'
]
};
const actualstr = JSON.stringify(jsonData);
const expectstr = JSON.stringify(expectData);
assert.deepInclude(jsonData, expectData, `acutal:${actualstr} | expect:${expectstr}`);
});
try it, and again , every thing looks just fine
至此,所有的2个请求的手工部分都做完了
这里我们要解决以下个关键问题,为自动化做好准备
- 分离数据: 数据会随着应用程序的更改而做出更改,直接写在请求里会非常的不方便,也不易于维护
- 分离环境配置: 各个测试环境会是用同样的测试用例,但是例如url等等会不同,需要能灵活的配置
手工测试的步骤里,其实把测试用例,数据,环境做到了一起,这一步我们来剥离他们。
- 分离数据:
我们希望把post请求的负载数据分离到数据文件里,并用于后面的验证步骤来用,创建一个data.json文件
[{
"newanimal": {
"name": "first animal",
"type": "cat",
"age": 2,
"likes": [
"fish", "mouse"
]
}
}]
此处添加newanimal字段,并把post请求的body复制过来放在这里
这里引入一个新的知识点"Pre-request Script",postman的执行顺序
- Pre-request Script
- 发送http请求
- Tests
由于Tests的脚本会在请求后做,一般我们会把验证都放在Tests里,Pre-request Script会在执行请求前做,我们用于数据的准备,就比如现在的情况,我们需要从data.json读取post请求需要的body数据来发送请求。
打开post请求,添加Pre-request Script代码
Pre-request Script代码
// 把数据文件里的newanimal字段读出来,并保存在body变量,此处data为固定名字,由postman创建,更改无效
const body = data.newanimal;
// 把body变量转换成字符串后设置到全局变量requestbody里
pm.globals.set("requestbody", JSON.stringify(body));
更改Tests代码
const chai = require('chai');
const assert = chai.assert;
pm.test("验证返回值201", function () {
pm.expect(pm.response.code).to.be.oneOf([200,201,202]);
});
pm.test("验证返回数据跟预想一致", function () {
const jsonData = pm.response.json();
// 预想值部分从data文件中读取
const expectData = data.newanimal;
const actualstr = JSON.stringify(jsonData);
const expectstr = JSON.stringify(expectData);
assert.deepInclude(jsonData, expectData, `acutal:${actualstr} | expect:${expectstr}`);
pm.globals.set("newid", jsonData.id);
});
同理修改get请求的Tests代码
const chai = require('chai');
const assert = chai.assert;
const expectid = pm.globals.get("newid");
pm.test("验证返回值200", function () {
pm.expect(pm.response.code).to.be.oneOf([200,201,202]);
});
pm.test("验证返回数据跟预想一致", function () {
const jsonData = pm.response.json();
// 预想值部分从data文件中读取
const expectData = data.newanimal;
// 预想值中没有id字段,我们需要对id做验证,添加id
expectData.id = expectid;
const actualstr = JSON.stringify(jsonData);
const expectstr = JSON.stringify(expectData);
assert.deepInclude(jsonData, expectData, `acutal:${actualstr} | expect:${expectstr}`);
pm.globals.set("newid", jsonData.id);
});
至此我们的测试代码里已经没有数据了,测试代码基本是一次成型无需修改,测试数据可以按需修改
当用到外部数据文件时,就不能通过send按钮来发起请求了,我们需要使用postman的Collection Runner
- 分离环境:
导出后为json文件,可以作为代码的一部分保存到代码仓库,其他开发人员可以在postman导入这个json文件进行编辑。另外如果有swagger,也可以从swagger文件导入生成api模板。
导出后也是json格式,打开一看应该就能明白,根据环境不同修改值即可
至此我们已经完成了3个主要的输入文件,测试case,数据,环境,这些文件都可以在sample目录下找到,这里补充上report模板mytemplat.hbs,如果需要定制,请自行编辑
在命令行终端,cd到你存放上述文件的目录中执行下面命令,执行完毕后,可以打开testreport.html看报告
newman run APITestGuide.postman_collection.json \
-d data.json \
-r htmlextra --reporter-htmlextra-export testreport.html \
--reporter-htmlextra-template mytemplat.hbs \
--environment myenv.postman_environment.json
命令说明
-
APITestGuide.postman_collection.json
指定测试case文件为,APITestGuide.postman_collection.json
-
-d data.json
指定数据文件
-
-r html --reporter-htmlextra-export testreport.html
指定report格式为html,输出到testreport.html
-
--reporter-htmlextra-template mytemplat.hbs
指定report模板为mytemplat.hbs,HTML模板可以根据项目需求自行定制
-
--environment myenv.postman_environment.json
指定环境配置文件为myenv.postman_environment.json
文件上传的请求,postman是不能正常导出的,上传的文件的信息会丢失,我们需要再DESCRIPTION字段留下文件名信息供自动化测试使用 在导出json文件后进行一次变换,变换需要用到cic工具包
安装
npm install -g @cic-digital/cic-tool-kit
变换
ctk editpostman --input=导出的json文件 --output=变换后的文件名
newman提供了多种形式report的支持,如果都不能符合客户需求,那么可以考虑选在json格式,导出原始数据,再自行定制如excel之类的结果报告
验证schema
const schema = {
"properties": {
id: {
"type": "number"
},
age: {
"type": "number"
},
likes: {
"type": "array",
"items": {
"type": "string"
}
},
name: {
"type": "string",
},
type: {
"type": "number",
},
}
};
const schemacheck = tv4.validate(jsonData, schema);
assert.strictEqual(true, schemacheck, `errormsg:${JSON.stringify(tv4.error)} | schema:${JSON.stringify(schema)} | actualData:${JSON.stringify(jsonData)}`);
验证html
// get http://www.baidu.com
const chai = require('chai');
const assert = chai.assert;
pm.test("title=百度一下,你就知道", function () {
const html = pm.response.text();
//类似jquery
const $ = cheerio.load(html);
const titleObject = $('title');
assert.equal(titleObject.text(), '百度一下,你就知道');
});
代码中添加console.log来输出需要的检查的变量到控制台
console.log(xxx)
希望你看完已经完全掌握api自动化测试,有问题联系[email protected]