自动化接口测试流程和工具说明
本文旨在描述基于POSTMAN的接口自动化测试方法,帮助大家完成接口单元测试,减少可恶的bug。
你需要准备的东西
1、接口文档(说明接口的访问方式、参数说明)
2、POSTMAN(我使用的Postman-win64-7.2.0-Setup)
3、csv编辑工具(我使用的RonsEditor_2019.10.22.0827_setup)
STEP 1 创建request collection
点击【Collections】切换到collection索引
点击【+ New Collection】新增collection,可以取中文名称
STEP 2 构建request请求
右键点击创建好的collection名称,选择【Add Request】
按照接口文档要求,配置好请求方式、请求URL
STEP 3 配置好请求参数
接口自动化测试与一般接口测试有所不同,请求参数是从测试用例中读取,因此需要将请求参数的各项配置成可变参数,本文以POST请求的json格式request body为例
参数变量表达式为{{parameter_name}}
例如:
{
"id":"{{id}}",
"name":"{{name}}",
"age":{{age}}
}
注意:
文本型需要用双引号,数值型不需要使用双引号
使用该变参形式后, 无法直接使用该接口进行测试
STEP 4 编写测试用例
测试用例支持json格式、txt格式和csv格式。
json格式为
[
//第一组测试用例
{
"id":"1",
"name":"xiaoming",
"age":10
},
//第二组测试用例
{
"id":"2",
"name":"xiaohong",
"age":12
},
...
]
多组测试用例以数组形式输入,每一个测试用例用json结构体表示。
csv/txt格式为
id,name,age
"1","xiaoming",10
"2","xiaohong",12
...
多组测试用例以行为单位,每项参数用,分开,第一行为参数名称。
无论是json还是csv/txt格式,测试用例的参数名必须和请求参数的{{parameter_name}}对应。
STEP 5 测试用例中使用变量
测试过程中,希望测试用例提供一些变参,比如说随机数、随机单词、当前日期等等,POSTMAN很好的支撑该功能哦。
{{$guid}}:生成V4风格随机ID,如: aa002-44ac-45ca-aae3-52bf19650e2d
{{$timestamp}}:将当前的时间戳,精确到秒
{{$randomInt}}:添加0和1000之间的随机整数
{{$randomLoremWord}}:生成随机英文单词
{{$randomAlphaNumeric}}:生成一个随机字母或数字
参数手册:https://learning.postman.com/docs/postman/variables-and-environments/variables-list/
使用变量的测试用例示例如下:
id,name,age
{{$randomInt}},name-{{$randomLoremWord}}{{$randomAlphaNumeric}},15
{{$randomInt}},name-{{$randomLoremWord}}{{$randomAlphaNumeric}},15
...
{{$XXX}}可以和其他字符串或变量进行拼接
STEP 6 测试用例编写方法(持续补充和完善ing)
1、增加测试说明
可以在测试用例中增加一项【testTarget】,说明该项测试用例的测试目的,方便测试人员了解测试目标和结果。
testTarget,id,name,age
测试正常输入参数,{{$randomInt}},name-{{$randomLoremWord}}{{$randomAlphaNumeric}},15
测试输入参数【name】长达大于最大长度,{{$randomInt}},name-{{$randomLoremWord}}{{$randomAlphaNumeric}},15
测试输入参数【name】包含特殊字符,{{$randomInt}},name-{{$randomLoremWord}}{{$randomAlphaNumeric}},15
...
2、文本型输入参数的测试用例
2.0 输入参数为正常值
2.1 输入参数长度小于最小长度
2.2 输入参数长度等于最小长度
2.3 输入参数长度等于最大长度
2.4 输入参数长度大于最大长度
2.5 输入参数包含特殊字符$、/、&、<、>、</br>、amp;
2.6 输入参数是特殊字符$、/、&、<、>、</br>、amp;
2.7 输入参数为空
2.8 输入参数重复
2.9 对输入参数有格式要求的,需要增加符合格式和不符合格式的测试用例
注意:\特殊字符会造成postman解析json异常,所以该项特殊字符的测试方法后续完善。
3、整数数值型输入参数的测试用例
2.0 输入参数为正常值
2.1 输入参数长度小于最小值
2.2 输入参数长度等于最小值
2.3 输入参数长度等于最大值
2.4 输入参数长度大于最大值
2.5 输入参数为非数字型文本
2.6 输入参数为数字型文本
2.7 输入参数为空
2.8 输入参数重复
2.9 对输入参数有格式要求的,需要增加符合格式和不符合格式的测试用例
4、枚举型输入参数的测试用例
2.0 输入参数为正常值
2.1 输入参数为异常值
4、list型输入参数的测试用例
2.0 输入参数为正常值
2.1 输入参数list长度小于最小值
2.2 输入参数list长度等于最小值
2.3 输入参数list长度等于最大值
2.4 输入参数list长度大于最大值
2.5 输入参数为[]
2.6 输入参数为[""]
2.7 输入参数为空
2.8 输入参数重复
STEP 7 测试脚本编写方法(持续补充和完善ing)
接口测试脚本输入框,右边有一些基础操作的示例,可以参考
测试脚本是对当前接口的一个测试用例的测试过程,比如10组测试用例该脚本会运行10次。
测试脚本1 显示本次测试目的,输入输出参数
//测试说明
pm.test("测试项:"+data.testTarget, function () {});
pm.test("测试数据:"+JSON.stringify(data), function () {});
pm.test("返回参数:"+pm.response.text(), function () {});
测试脚本2 测试响应时延
//测试说明
pm.test("响应时间小于200ms", function () {
pm.expect(pm.response.responseTime).to.be.below(200);
});
pm.test("响应时间小于1s", function () {
pm.expect(pm.response.responseTime).to.be.below(1000);
});
pm.test("响应时间小于5s", function () {
pm.expect(pm.response.responseTime).to.be.below(5000);
});
测试脚本3 获取当前测试用例的接口输入参数和接口输出参数
//获取响应结果
var responseBody = pm.response.json();
//获取请求数据
var requestBody=data;
pm.test("返回体包含code", function () {
pm.expect(pm.response.text()).to.include("code");
});
pm.test("返回体包含msg", function () {
pm.expect(pm.response.text()).to.include("msg");
});
var code=responseBody.code;
var msg=responseBody.msg;
//获取参数和格式转化
var input_id=requestBody.id+'';//转化为字符串形式
var input_name=requestBody.name+'';
var input_age=requestBody.age;
var input_catalogueList=requestBody.catalogueList;//list型参数,需要做json转化:JSON.parse(xxx)
测试脚本4 测试必填字段
//测试必填字段未输入
testRequiredfield(input_name,"数据源名称","0007");
testRequiredfield(input_type,"数据类型","0007");
//测试必填项参数
function testRequiredfield(input,name,errorCode){
if (input===null||input.length===0) {
pm.test("测试输入参数【"+name+"】为空,返回参数异常错误码", function () {
pm.expect(code).to.include(errorCode);
});
pm.test("测试输入参数【"+name+"】为空,返回参数异常信息", function () {
pm.expect(msg).to.include(""+name+"不能为空");
});
}
}
测试脚本5 测试文本型字段
//测试文本型输入参数
testStringfield(input_name,"数据源名称",0,200,"0007");
testStringfield(input_memo,"数据源描述",0,1000,"0007");
//测试文本类参数
function testStringfield(input,name,minLength,maxLength,errorCode){
if (input.length<minLength) {
pm.test("测试输入参数【"+name+"】小于最小长度,返回参数异常信息", function () {
pm.expect(code).to.include(errorCode);
});
}
if (input.length===minLength) {
pm.test("测试输入参数【"+name+"】等于最小长度,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input.length===maxLength) {
pm.test("测试输入参数【"+name+"】长度等于最大长度,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input.length>maxLength) {
pm.test("测试输入参数【"+name+"】长度大于最大长度,返回参数异常信息", function () {
pm.expect(code).to.include(errorCode);
});
}
if (input.startsWith(' ')) {
pm.test("测试输入参数【"+name+"】以空格开头,返回参数异常信息", function () {
pm.expect(code).to.include(errorCode);
});
}
if (input.endsWith(' ')){
pm.test("测试输入参数【"+name+"】以空格结束,返回参数异常信息", function () {
pm.expect(code).to.include(errorCode);
});
}
if (input.indexOf(' ')>minLength&&input.indexOf(' ')<input.length-1){
pm.test("测试输入参数【"+name+"】包含空格,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input.indexOf('>')>=0){
pm.test("测试输入参数【"+name+"】包含>,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input==='>'){
pm.test("测试输入参数【"+name+"】为>,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input.indexOf('<')>=0){
pm.test("测试输入参数【"+name+"】包含<,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input==='<'){
pm.test("测试输入参数【"+name+"】为<,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input.indexOf('&')>=0){
pm.test("测试输入参数【"+name+"】包含&,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input==='&'){
pm.test("测试输入参数【"+name+"】为&,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input.indexOf('?')>=0){
pm.test("测试输入参数【"+name+"】包含?,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input==='?'){
pm.test("测试输入参数【"+name+"】为?,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input.indexOf('/')>=0){
pm.test("测试输入参数【"+name+"】包含/,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input==='/'){
pm.test("测试输入参数【"+name+"】为/,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input.indexOf('amp;')>=0){
pm.test("测试输入参数【"+name+"】包含amp;,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input==='amp;'){
pm.test("测试输入参数【"+name+"】为amp;,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input.indexOf('</br>')>=0){
pm.test("测试输入参数【"+name+"】包含</br>,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input==='</br>'){
pm.test("测试输入参数【"+name+"】为</br>,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input.indexOf('</br>')>=0){
pm.test("测试输入参数【"+name+"】包含</br>,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (input==='</br>'){
pm.test("测试输入参数【"+name+"】为</br>,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
}
测试脚本6 测试整数型字段
//测试数值类输入参数
testNumfield(input_port,"数据源端口",0,65535,"0007");
//测试整数参数
function testNumfield(input,name,minValue,maxValue,errorCode){
if(input ==null||input === ""){
pm.test("测试输入参数【"+name+"】输入为空,返回参数异常信息", function () {
pm.expect(code).to.include(errorCode);
});
}
var r = /^\+?[1-9][0-9]*$/;
if(r.test(input)||input==='0'||input===0){
var val=parseInt(input);
if (val<minValue) {
pm.test("测试输入参数【"+name+"】小于最小值,返回参数异常信息", function () {
pm.expect(code).to.include(errorCode);
});
}
if (val===minValue) {
pm.test("测试输入参数【"+name+"】等于最小值,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (val===minValue) {
pm.test("测试输入参数【"+name+"】等于最大值,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if (val>maxValue) {
pm.test("测试输入参数【"+name+"】大于最大值,返回参数异常信息", function () {
pm.expect(code).to.include(errorCode);
});
}
}else{
pm.test("测试输入参数【"+name+"】不是整数,返回参数异常信息", function () {
pm.expect(code).to.include(errorCode);
});
}
}
测试脚本7 测试枚举型参数
//测试枚举型输入参数
testEnumfield(input_type,"数据源类型",["mysql","hive","mongodb","kafka","api"],"0007");
//测试枚举型参数
function testEnumfield(input,name,enumValue,errorCode){
var result=false;
for (var i =0; i< enumValue.length; i++) {
if (input===enumValue[i]) {
result=true;
}
}
if (true) {
pm.test("测试输入参数【"+name+"】为正常值,返回操作成功", function () {
pm.expect(code).to.include("0000");
});
}else{
pm.test("测试输入参数【"+name+"】为异常,返回操作成功", function () {
pm.expect(code).to.include("0007");
});
}
}
测试脚本8 测试列表型参数
//测试列表型输入参数
testListField(input_catalogueList,"数据源分类列表",0,1,"0007");
//测试列表型参数
function testListField(input,name,minLength,maxLength,errorCode){
var list =JSON.parse(input);
if(list ==null||list === ""){
pm.test("测试输入参数【"+name+"】输入为空,返回参数异常信息", function () {
pm.expect(code).to.include(errorCode);
});
}
if(list.length===0){
pm.test("测试输入参数【"+name+"】为空列表,返回参数异常信息", function () {
pm.expect(code).to.include(errorCode);
});
}
if(list.length<minLength){
pm.test("测试输入参数【"+name+"】列表长度小于最小值,返回参数异常信息", function () {
pm.expect(code).to.include(errorCode);
});
}
if(list.length===minLength){
pm.test("测试输入参数【"+name+"】列表长度等于最小值,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if(list.length===maxLength){
pm.test("测试输入参数【"+name+"】列表长度等于最大值,返回操作成功", function () {
pm.expect(code).to.include(successCode);
});
}
if(list.length>maxLength){
pm.test("测试输入参数【"+name+"】列表长度大于最大值,返回参数异常信息", function () {
pm.expect(code).to.include(errorCode);
});
}
}
测试脚本9 测试其他逻辑
if(xxx){
pm.test("xxx", function () {
pm.expect(pm.response.text()).to.include("xxx");
});
}
测试脚本10 测试返回体结构
if(code=="0000"){
pm.test("返回体包含data", function () {
pm.expect(pm.response.text()).to.include("data");
});
}
STEP 8 开始测试!!!
8.1 将编写的测试脚本全部复制到
8.2点击runner
8.3选择测试参数
8.4测试中
STEP 9 查看测试结果
查看输入参数
查看返回参数
查看测试结果
STEP 10 迭代测试!!!
要对该接口进行重新测试时,如果修改输入参数和测试脚本,在接口编辑界面修改保存后即可,测试用例修改后直接保存即可
重新测试不能直接点【retry】,这样无法获取到测试用例数据!!!
需要点击【New】,重新选择测试接口,其他参数不用修改,重新测试