基于POSTMAN的自动化接口测试流程和方法(单元测试)

自动化接口测试流程和工具说明

本文旨在描述基于POSTMAN的接口自动化测试方法,帮助大家完成接口单元测试,减少可恶的bug。

你需要准备的东西
1、接口文档(说明接口的访问方式、参数说明)
2、POSTMAN(我使用的Postman-win64-7.2.0-Setup)
3、csv编辑工具(我使用的RonsEditor_2019.10.22.0827_setup)

STEP 1 创建request collection

image.png

点击【Collections】切换到collection索引
点击【+ New Collection】新增collection,可以取中文名称


image.png

STEP 2 构建request请求

右键点击创建好的collection名称,选择【Add Request】


image.png

按照接口文档要求,配置好请求方式、请求URL


image.png

STEP 3 配置好请求参数

接口自动化测试与一般接口测试有所不同,请求参数是从测试用例中读取,因此需要将请求参数的各项配置成可变参数,本文以POST请求的json格式request body为例


image.png

参数变量表达式为{{parameter_name}}
例如:

{
    "id":"{{id}}",
     "name":"{{name}}",
    "age":{{age}}
}

注意:
文本型需要用双引号,数值型不需要使用双引号
使用该变参形式后, 无法直接使用该接口进行测试


image.png

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次。


image.png

测试脚本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 将编写的测试脚本全部复制到


image.png

8.2点击runner


image.png

8.3选择测试参数


16816114-696d55e5a4f1b77e.png

8.4测试中

STEP 9 查看测试结果

查看输入参数


image.png

查看返回参数


image.png

查看测试结果


image.png

STEP 10 迭代测试!!!

要对该接口进行重新测试时,如果修改输入参数和测试脚本,在接口编辑界面修改保存后即可,测试用例修改后直接保存即可
重新测试不能直接点【retry】,这样无法获取到测试用例数据!!!
需要点击【New】,重新选择测试接口,其他参数不用修改,重新测试

image.png

STEP 11 根据测试结果修改bug,加油~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容