https://www.getpostman.com
require()
import
等除外) 选它的做自动化测试的理由:
不选它的理由:
https://www.getpostman.com/apps
建议选择Mac/Windows app,比起Chrome app,下载不需要翻墙,功能更强大
官方文档
教程
[API 测试]postman , 2016-02-29
API自动化测试利器——Postman , 2015-09-26(教程里的版本比较旧了,但还是讲得不错)
How to write powerful automated API tests with Postman, Newman and Jenkins , 2015-09-03
How to write automated tests for APIs using Postman – Part 1 , 2014-03-07
How to write automated tests for APIs with Postman – Part 2 , 2014-04-17
Writing automated tests with Postman – Part 3 , 2014-05-09
示例
Postman Echo
Making the perfect HTTP request using Postman Echo , 2015-11-13
Cooper's Meal Plan
Conditional Workflows in Postman , 2016-03-23
Spotify Playlist Generator
Generate Spotify Playlists using a Postman Collection , 2016-11-09
CurencyCloud的 Postman集合 和 使用说明
Capturing requests (native app)
Using Postman Proxy to Capture and Inspect API Calls from iOS or Android Devices ,2016-06-26
接口调用方希望测试业务逻辑时,用不着Fiddler/Charles抓包再往里面一个个填这么麻烦
开启Postman的代理(默认5555端口),浏览器/手机设好对应的IP和端口就行
支持正则表达式过滤URL,建议排除掉静态资源、流量统计站和别的后台进程时不时请求的网站
baidu|google|microsoft|github|qq/.com|.*/.(html?|css|js|png|jpe?g|webp|ico)$
可以设置保存的位置:
如果所有操作步骤都要做接口测试,建议直接保存到目标集合
如果一大堆操作里只取其中一个到几个接口,建议保存到历史记录,挑出想要的另存到目标集合,不用浪费时间删
Running a collection
【特别注意】
Postman/Newman是用JS写的,批量执行的最小粒度是文件夹
单线程异步的性质决定了 文件夹的执行顺序跟看上去的排列顺序没有任何关系
只有同一文件夹内的用例,或直接放集合下的用例,执行的顺序跟看上去的顺序一样
每个集合测1个方面,集合内每个文件夹测1个完全独立的子场景
此外
/path/to/api 接口描述
,方便看和搜索 只有在collection runner或Newman里才生效(在普通界面你选哪个发送就是哪个)
/* 假设2个用例的顺序为: 用例A 用例B 如果希望执行顺序为: 用例A -> 用例B -> 用例A,又不想复制一份用例A,那么 */ // 用例A的Tests里写 if (xxx) postman.setNextRequest('null'); // 终止执行 // 用例B的Tests里写 postman.setNextRequest('用例A'); // 【注意】如果不设终止条件,用例A执行完到用例B,用例B执行完又指向用例A,会构成死循环 // PS:postman是Postman提供的全局变量
Testing Sandbox 内建对象、方法、变量和可用的第三方库介绍
Testing examples
Extracting data from responses and chaining requests , 2014-10-27
在主界面可以靠肉眼看返回结果,但在collection runner/Newman里如果不加断言,跑完没法知道是成功还是失败
断言写在 Tests
标签页里,上手可以参考文档和界面右边的代码模板:
tests['Status code is 200'] = responseCode.code === 200; // 推荐用全等 ===,确保类型和值都一致 tests['Response time is less than 200ms'] = responseTime < 200; tests['Body matches string'] = responseBody.has('xxx'); // 只要有指定关键字就行,在哪、有几个等都不管 tests['Content-Type is present'] = postman.getResponseHeader('Content-Type') || false; // Postman的断言实际上就是往 tests 对象添加键值对 // 它的key会显示在报告界面上,value是可以解析为boolean的表达式 // 如果得出的值是true,在报告里显示为成功,false失败 // 【变通】用总是为真的断言来显示信息 tests[`[INFO] Request params: ${JSON.stringify(request.data)}`] = true; // 显示所有请求参数(在自动化测试里很有用) tests[`跑第${iteration + 1}次`] = true; // 用在runner里循环很多次时(iteration是迭代次数,从0开始) // PS:tests、responseCode、responseTime、responseBody、postman、request、iteration是Postman提供的全局变量 // 【注意】如果你在做自动化测试,目前在接口超时没返回时: // responseCode、responseTime、responseBody都没定义,调用(包括判断是否undefined)时会导致脚本出错,判断是否超时没返回的只能靠header // request.data里的变量在超时时不解析,很容易让人误会请求参数传错了,建议此时不显示这行
返回JSON时
let json = JSON.parse(responseBody); // responseBody是包含整个返回内容的字符串 // 提取某字段的值: let foobar = json.foo.bar[0].foobar; // 假设结构为 {"foo": {"bar": [{"foobar": 1}, {"baz": 2}]}} // 想用在自动化测试可以多写点: let json; try { json = JSON.parse(responseBody); } catch (err) { tests['Expect response body to be valid JSON'] = false; tests[`Response body: ${responseBody}`] = true; console.error(err); }
返回HTML时
// A. 用正则表达式匹配 let foo = responseBody.match(/foo/g); // g 全局 i 不分大小写 m 多行 tests['blahblahblah'] = foo[0] === 'bar'; // 正则里包含变量时: let foo = 'xxx'; let bar = responseBody.match(new RegExp(`^${foo}.*$`, 'g'); // B. 用CheerioJS库: let html = cheerio(responseBody); let titleText = html.find('title').text(); // 取 <title>标签里的文字
jQuery replaced by CheerioJS in Postman Sandbox , 2016-08-30
Setting up an environment with variables
Postman的环境变量分为 environment 和 global 2种
实际上就是 environment
、 globals
这2个全局的对象(字典)里的内容
它们的key作为变量名,value作为变量的值
满足99%的需要,平时只用它就够了,global留到后文讲
在地址栏、header、请求参数、外部数据文件里,用 {{变量名}}
获取环境变量的值
如: {{URL}}/path/to/api
在 Pre-request Script
和 Tests
的代码里略有不同:
/* 官方提供的方法 */ // 设置 postman.setEnvironmentVariable('variableKey', value); // 注意:通过菜单或以上方法设置的环境变量,值会转成字符串,取的时候要转换 // 获取 let foo = postman.getEnvironmentVariable('variableKey'); // 字符串数字转数字:Number(foo) // 字符串'true' 'false'转布尔值:Boolean(foo) 或 !!foo // 更新 // 就是再设置一次同名的环境变量,换别的值 // 清除环境变量 postman.clearEnvironmentVariable('variableKey');
/* 懒人版 */ // 既然知道实际上是操作 environment 对象,如果你有JS基础,可以直接: // 添加key environment.variableKey = 12345; // 少打字,取出时也不用转换类型 // 获取 let foo = environment.variableKey; // 清除 delete environment.variableKey; // 如果你非要跟自己过不去,用了变量名不允许的字符做key(比如有空格),只能写成 environment['variableKey'] // 只要没跟自己过不去,可以用ES6的对象解构语法一次取多个: let {key1, key2, key3} = environment;
【注意】
在Postman主界面运行过后,通过代码设置的环境变量会存到IndexedDB,跟在菜单里设置一样,用例跑完不消失
但在collection runner或Newman跑则是默认不保存,跑完就消失,做自动化测试时要注意
在runner里循环发n次请求/做自动化测试时,有些接口不适合写死参数
{{$guid}} // 生成GUID {{$timestamp}} // 当前时间戳 {{$randomInt}} // 0-1000的随机整数
上个请求的 Tests
里提取参数存环境变量,这个请求里用 {{变量名}}
取值
在 Pre-request Script
里写代码处理,存为环境变量,参数里用 {{变量名}}
取值
例如
const randomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min; // 随机整数 const getRandomValue = list => list[randomInt(0, list.length - 1)]; // 随机选项 // 随机手机 environment.randomMobile = `18${randomInt(100000000, 999999999)}`; // 随机设备名 environment.randomDevice = getRandomValue(['ios', 'android']);
Postman目前没有很方便的重用代码的手段,编辑框也不是IDE,没智能提示,尽量别整那么复杂
cmd + alt + c
(Windows ctrl + alt + c
)打开Postman控制台,可以看请求和响应内容
用 console.log()
打印,到控制台看
或 tests['这里拼出你想看的字符串'] = true
在界面/报告看断言
Using a mocking service to create Postman Collections ,2016-01-26
跟environment几乎完全一样,在地址栏、header、请求参数、外部数据文件里也是 {{}}
调用,除了:
global只建议用在1种场景: 定义公共函数
先正常地写好函数,再用 在线压缩工具 压成一行
在菜单里选 Bulk Edit,以每行一对 key:value 的形式编辑,变量名做key,函数做value
assertNotTimeout:var hasResponse=postman.getResponseHeader('Content-Type')?true:false; if(!hasResponse) tests['服务端在超时前没返回任何数据,请检查相关服务、网络或反向代理设置(以下跳过其他断言)']=false; logParams:if(hasResponse) tests[`[INFO] 请求参数(超时没返回时不解析):${JSON.stringify(request.data)}`]=true; getResponseJson:try{if(hasResponse) var json=JSON.parse(responseBody);}catch(err){ tests['服务端没返回合法的JSON格式,请检查相关服务、网络或反向代理设置(以下跳过其他断言)']=false; tests[`[INFO] 返回:${responseBody}`]=true; console.error(err);} assertType:var assertType=(name,value,type)=>{let isType=(type==='array')? Array.isArray(value):typeof value===type; tests[`${name}为${type}(实际值:${value})`]=isType;}; assertEqual:var assertEqual=(name,actual,expected)=>{tests[`${name}等于${expected}(实际值:${actual})`]=actual===expected;}; assertNotEqual:var assertNotEqual=(name,actual,expected)=>{tests[`${name}不等于${expected}(实际值:${actual})`]=actual!==expected;}; // 注意在这里定义变量只有 var 的作用域够大,用 let 或 const 的话eval后就销毁了
假设返回 {"name":"张三","userType":1,"settings":[]}
,在 Tests
里一上来就写:
eval(globals.assertNotTimeout); // 判断是否超时(通过有没有Content-Type请求头),超时则断言失败 eval(globals.logParams); // 如果不超时,显示发出的请求参数 eval(globals.getResponseJson); // 如果不超时,解析返回的JSON对象,赋给json变量,返回值不合法则断言失败 // 下面定义了3个公共函数,免得每次断言都要写一大串: eval(globals.assertType); eval(globals.assertEqual); eval(globals.assertNotEqual); // 基本满足日常使用需要 assertType('用户名', json.name, 'string'); // 在报告中显示为: '用户名为string,(实际值:张三)' assertType('设置', json.settings, 'array'); // JS里其实没有array类型(数组是object),这里做了处理,让报告更好懂 assertEqual('用户类型', json.userType, 1); // 显示为: '用户类型等于1,(实际值:1)' assertNotEqual('用户类型', json.userType, 2); // 显示为: '用户类型不等于2,(实际值:1)'
在官方给出更方便的重用代码的方法前,这是除了复制粘贴外唯一的重用方法
如果不做自动化测试,且断言写得很简单,不建议这么搞
如果不幸跳了自动化的坑,通常一个项目会有100~200个接口要做自动化测试,要仔细比较哪种方法成本更高
定义函数前要仔细考虑好,万一中途要改参数和返回值,已经写好的n份也得改……
建议定义的公共函数不超过个位数,并保留好没压缩的版本,不然别人没法接手
Writing a behaviour driven API testing environment within Postman
// 如果确实要在代码里设global // 官方的: postman.setGlobalVariable('variableKey', value); // 同样存成字符串 let bar = postman.getGlobalVariable('variableKey'); postman.clearGlobalVariable('variableKey'); // 或者自己操作 globals 对象
Using data variables to run a collection multiple times
Using CSV and JSON data files in the Postman Collection Runner , 2014-10-28 Using variables inside Postman and Collection Runner , 2014-02-20
在collection runner或命令行的Newman里可以加载数据文件
/* JSON格式 */ // 文件里有且只有1个数组,每个对象算1条用例(在Postman里的全局变量叫做data) // key作为变量名,value作为变量的值 // 文件里依然可以用 {{}} 拿到环境变量,注意不要把自己绕进去: // 如果是Pre-request Script里生成的环境变量,直接写进请求参数,不用经这里 [ {"mobile": "17000000001", "pwd": "123456"}, {"mobile": "17000000002", "pwd": "654321"}, {"mobile": "17000000003", "pwd": ""}, {"mobile": "{{ADMIN_MOBILE}}", "pwd": "{{ADMIN_PWD}}"} ] // 显然,这是json文件,并不能在里面写代码(除非你蛋疼在value里写字符串然后在用例里eval) // 用例的请求参数里依然用 {{key}} 拿到数据文件里的值,代码里则是 data.key // 如果key跟environment/globals里的key重名,这里 > environment > globals /* CSV格式 */ // 第1行变量名,下面是值,每行1条用例,没有空格 // 没JSON格式的数据文件灵活 mobile,pwd 17000000001,123456 17000000002,654321 17000000003,
【注意】
谨慎使用。这东西增加了调试和定位问题的复杂性,也就大大增加了维护成本
而它带来的收益并不明显:
Postman不是正经的压测工具,既然选择了它就是图简单方便
像JMeter那样用CSV文件做数据源的意义不大,还得另外写程序/脚本生成这样的文件,时间上不划算
直接用代码生成数据就好,不差那一两毫秒
很诱人,但是
如果不确定有些输入要不要/怎么处理,意味着改动可能会非常大
今天非法,明天变合法,后天又变非法
如果冒烟用例用在持续集成,有测试不通过会阻止发布,会严重干扰正常发版,也影响大家对自动化测试的信心
此外
不要因为所谓“测试思维”,就在不了解的情况下为了测试而测试
这种力气留到探索性测试和安全测试,自动化测试还是要讲求稳定和省事
此外
然后你回过头发现,一开始不用数据文件不就省事多了?!
目前管理员不能解散自己创建的团队,不能删别人创建的环境变量模板,几乎残废
不是太推荐交钱
New, More Useful Activity Feed in Postman Collections , 2016-10-27
Announcing: Environment Sharing! , 2016-03-10
例如你要发布SDK,页面里可以带上跑Postman测试的按钮
Call for Partners: The Run in Postman Button for API documentation