要想实现接口的自动化测试,需要以下几个步骤:
自动登录
首先点击postman左上角的new按钮,创建一个collection,在pre-request-scripts标签下,给整个collection创建一个公用规则


编写登录脚本
pre-request-scripts在请求发送前执行的脚本,在整个集合期间只会执行一次;
在集合变量(参考上图)中添加对应的用户名和密码
//获取集合
const { host, username, password } = pm.collectionVariables.toObject();
使用pm.sendRequest方法发送一个ajax请求,将请求成功的结果的token值存到环境变量中。
const data = res.json();
pm.environment.set("token", data.data["X-Access-Token"]);
完整代码如下:
const {// host,yapiToken,yapiHost,variable_key,token,catid,CooperationPlatformId
} = pm.variables.toObject();const { host, username, password } = pm.collectionVariables.toObject();
const echoPostRequest = {url: `${host}/api/login`,method: 'POST',header: 'Content-Type: application/json;charset=UTF-8',body: {mode: 'raw',raw: JSON.stringify({ username, password})}
};
//使用pm.sendRequest方法发送一个ajax请求,
if(!token){pm.sendRequest(echoPostRequest, function (err, res) {console.log(err ? err : res.json());const data = res.json();pm.environment.set("token", data.data["X-Access-Token"]); });
}

yapi,去哪网出的开源的可视化接口管理平台,推荐部署到公司服务器,也可以直接使用官方的。
YApi-高效、易用、功能强大的可视化接口管理平台yapi.demo.qunar.com
schema格式的约束文件,值得推荐的地方就是对mockjs语法支持的很好。
{"type": "object","title": "empty object","properties": {"data": {"type": "object","properties": {"name": {"type": "string","mock": {"mock": "@string"}}},"required": ["name"]},"code": {"type": "string","mock": {"mock": "@natural"}},"msg": {"type": "string","mock": {"mock": "@string"}}},"required": ["data","code","msg"]
}获取接口的schema文件
yapi的开发api很方便的获取接口相关的信息。
//生成分类下接口列表的map对象
const genCatInterfaceListMap = function (catid) {return new Promise(function (resolve, reject) {const url = `${yapiHost}/api/interface/list_cat?token=${yapiToken}&catid=${catid}&limit=100`;pm.sendRequest(url, function(err, res){if(err){console.log("err: ", err)}else{var data = res.json();var list = data.data.list;var catInterfaceListMap = list.reduce((acc, item) => {var key = item.path.slice(1).split("/").join("_");acc[key] = item._id;return acc;}, {})resolve(catInterfaceListMap);}})});
};
获取指定分类下的接口列表,并存到集合变量中。
genCatInterfaceListMap(catid).then((newMap) => {let catInterfaceListMap = pm.collectionVariables.get("catInterfaceListMap") || {};pm.collectionVariables.set("catInterfaceListMap", Object.assign({}, catInterfaceListMap, newMap));
});genCatInterfaceListMap(CooperationPlatformId).then((newMap) => {let catInterfaceListMap = pm.collectionVariables.get("catInterfaceListMap") || {};pm.collectionVariables.set("catInterfaceListMap", Object.assign({}, catInterfaceListMap, newMap));
})
关键环节来了从yapi获取接口的schema,并验证格式
//验证数据格式测试用例。
pm.test("数据格式正确", () => {var valid = validate(pm.response.json());if(!valid){console.log("validate.errors", validate)validate.errors.forEach(function(item){console.log(item.dataPath, ":", item.message);})}pm.expect(valid).to.be.true
})
使用avj来做校验;
var Ajv = require('ajv');
var ajv = new Ajv(); // options can be passed, e.g. {allErrors: true}
var validate = ajv.compile(schema);
var valid = validate(data);
if (!valid) console.log(validate.errors);
完整代码
在collection的Tests tab下,编写下面代码
//从yapi 服务上获取到了对应的schema,检验接口返回值是否匹配schema
var Ajv = require("ajv");
var ajv = new Ajv({logger: console, allErrors: true});
const { path } = pm.request.url;
const yapiToken = pm.variables.get("yapiToken")
const pathKey = path.slice(-3).join("_");
const catid293 = pm.variables.get("catid293");
const interfaceId = catid293[pathKey];console.log("path:Test", pathKey, catid293, interfaceId);
const url = `http://yapi.ops.tst-weiboyi.com/api/interface/get?token=${yapiToken}&id=${interfaceId}`;//从yapi接口中获取当前接口的schema
pm.sendRequest(url, function(err, res){if(err){console.log("err: ", err)}else{var data = res.json();var schema = JSON.parse(data.data.res_body);delete schema["$schema"];var validate = ajv.compile(schema);pm.test("数据格式正确", () => {var valid = validate(pm.response.json());if(!valid){console.log("validate.errors", validate)validate.errors.forEach(function(item){console.log(item.dataPath, ":", item.message);})}pm.expect(valid).to.be.true}) }
})
输出错误信息
还有其他方法和参数,默认validate.errors虽然是个数组,但里面默认只包含了第一条错误。具体能否输出所有不匹配字段,还待研究?
补充:
//allErrors 默认为false,只能显示一条信息
var ajv = new Ajv({logger: console, allErrors: true});
使用变量作为请求参数
(function(){const data = pm.response.json();const list = data.data.list;//获取满足指定操作条件的idconst okIds = list.filter(item => item.type == 1).map(item => item.id);const passIds = list.filter(item => item.type == 2).map(item => item.id);const [ okId ] = okIds;const [ passId ] = passIdspm.collectionVariables.set("customId", okId);pm.collectionVariables.set("passId", passId);
})()
可以在下个请求中使用上个请求存储的变量
{"type":"2", "remark":"1111", "id": {{okId}}
}
在body里面获取变量注意事项
pm.collectionVariables.set("ids", [1,2,3]);
//在body里面需要这样写
{"ids":{{ids}}
}
自动化批量测试


查看格式报错
在postman的控制台,可以显示所有格式错误的log

其他的集合测试用例
在编辑集合的弹窗里面,Tests标签下,可以编写公共测试用例,集合下的每个请求都会执行
pm.test("Status code is 200", function () {pm.response.to.have.status(200);
});pm.test('状态码为1000', () => {var d = pm.response.json();pm.expect(d.code).to.equal("1000")
})pm.test("Response time is less than 200ms", function () {pm.expect(pm.response.responseTime).to.be.below(200);
});//清除全局变量
pm.globals.unset("variable_key");pm.test("Content-Type is present", function () {pm.response.to.have.header("Content-Type");
});编写单个请求的测试用例
在每个请求的Tests标签下,可以编写脚本,这个是请求成功后执行的代码
//获取变量
const aId = pm.collectionVariables.get("accountId");console.log("aId", aId)
//编写测试用例
pm.test(`上架成功, id: ${aId}`, () => {//将返回值转换为json对象var d = pm.response.json();//验证返回值的code值是否是1000pm.expect(d.code).to.equal("1000")
})相关文档
pm.expect语法相关文档 chaijs BDD(想弄明白,就仔细看一遍这个文档)
BDD
The BDD styles are expect and should. Both use the same chainable language to construct assertions, but they differ in the way an assertion is initially constructed. Check out the Style Guide for a comparison.
API Reference
Language Chains
The following are provided as chainable getters to improve the readability of your assertions.Chains
- to
- be
- been
- is
- that
- which
- and
- has
- have
- with
- at
- of
- same
- but
- does
- still
.not
Negates all assertions that follow in the chain.
expect(function () {}).to.not.throw();
expect({a: 1}).to.not.have.property('b');
expect([1, 2]).to.be.an('array').that.does.not.include(3);
以下是文档相关内容,postman-sanbox-api-reference;(pm对象的相关属性)
在postman的沙箱内有几个作用域
优先顺序是Iteration Data<Environment<Collection<Global。四个作用域分别对应下面四个变量。
pm.variables,在 pre-request scripts中pm.variables.set("path", "/api/xxx"),在Test中可以通过pm.variables.get("path")获取到
pm.variables
pm.variables: 阅读有关VariableScope的更多信息
在Postman中,所有变量都符合特定的层次结构。当前迭代中定义的所有变量优先于当前环境中定义的变量,当前环境中的变量将覆盖全局范围中定义的变量。优先顺序是Iteration Data< Environment< Collection< Global。
pm.variables.has(variableName:String):function → Boolean:检查当前作用域中是否存在局部变量。pm.variables.get(variableName:String):function → *:获取具有指定名称的局部变量的值。pm.variables.toObject():function → Object:返回包含本地范围内所有变量的对象。pm.variables.set(variableName:String, variableValue:String"):function → void:使用给定值设置局部变量。
还可通过pm.environment环境范围和pm.globals全局范围访问在各个范围中定义的变量。
pm.environment
pm.environment: 阅读有关VariableScope的更多信息
pm.environment.name:String:包含当前环境的名称。pm.environment.has(variableName:String):function → Boolean:检查环境是否具有具有给定名称的变量。pm.environment.get(variableName:String):function → *:获取具有给定名称的环境变量。pm.environment.set(variableName:String, variableValue:String):function:使用给定的名称和值设置环境变量。pm.environment.unset(variableName:String):function:删除具有指定名称的环境变量。pm.environment.clear():function:清除所有当前环境变量。pm.environment.toObject():function → Object:以单个对象的形式返回所有环境变量。
pm.collectionVariables
pm.collectionVariables: 阅读有关VariableScope的更多信息
pm.collectionVariables.has(variableName:String):function → Boolean:检查是否存在具有给定名称的集合变量。pm.collectionVariables.get(variableName:String):function → *:返回具有给定名称的collection变量的值。pm.collectionVariables.set(variableName:String, variableValue:String):function:设置具有给定值的集合变量。pm.collectionVariables.unset(variableName:String):function:清除指定的集合变量。pm.collectionVariables.clear():function:清除所有集合变量。pm.collectionVariables.toObject():function → Object:以对象的形式返回变量及其值的列表。
pm.globals
pm.globals: 阅读有关VariableScope的更多信息
pm.globals.has(variableName:String):function → Boolean:检查是否存在具有给定名称的全局变量。pm.globals.get(variableName:String):function → *:返回具有给定名称的全局变量的值。pm.globals.set(variableName:String, variableValue:String):function:设置具有给定值的全局变量。pm.globals.unset(variableName:String):function:清除指定的全局变量。pm.globals.clear():function:清除所有全局变量。pm.globals.toObject():function → Object:以对象的形式返回变量及其值的列表。
pm.request
pm.request: 阅读有关VariableScope的更多信息
request内部的对象pm表示正在为此脚本运行的请求。对于请求前脚本,这是将要发送的请求,在测试脚本中时,这是已发送请求的表示。
request 包含以以下结构存储的信息:
pm.request.url:Url:包含发出请求的URL。pm.request.headers:HeaderList:包含当前请求的标头列表。pm.request.headers.add(headerName:String):function:为当前请求添加具有指定名称的标头。pm.request.headers.delete(headerName:String):function:删除具有当前请求的指定名称的标头。pm.request.headers.upsert({ key: headerName:String, value: headerValue:String}):function):插入给定当前请求的标题列表的标题名称和标题值(如果标题不存在,否则将已存在的标题更新为新值)。
以下项目仅在测试脚本中可用。
pm.response
pm.response: 阅读有关响应的更多信息
在测试脚本中,该pm.response对象包含与收到的响应有关的所有信息。
响应详细信息以以下格式存储:
pm.response.code:Numberpm.response.reason():Function → Stringpm.response.headers:HeaderListpm.response.responseTime:Numberpm.response.text():Function → Stringpm.response.json():Function → Object
pm.iterationData
pm.iterationData: 阅读有关VariableScope的更多信息
该iterationData对象包含在收集运行期间提供的数据文件中的数据。
pm.iterationData.get(variableName:String):function → *:从迭代数据中返回具有指定名称的变量。pm.iterationData.toObject():function → Object:将迭代数据作为对象返回。pm.iterationData.addLayer(list: VariableList):function → void:将变量列表添加到迭代数据。pm.iterationData.clear():function → void:清除所有数据。pm.iterationData.has(variableName: string):function → boolean:检查迭代数据中是否存在具有指定名称的变量。pm.iterationData.set(key: string, value: any, type: string):function → void:设置变量,为其指定值和类型。pm.iterationData.syncVariablesFrom(object: {[key: string]: VariableDefinition}, track?: boolean, prune?: boolean):function → Object | Undefined:从具有指定名称的对象获取变量。pm.iterationData.syncVariablesTo(object?: {[key: string]: VariableDefinition}):function → Object:将变量保存到具有指定名称的对象。pm.iterationData.toJSON():function → *:将迭代数据对象转换为JSON格式。pm.iterationData.unset(key: string):function → void:取消分配给指定变量的值。pm.iterationData.variables():function → Object:从erationData对象返回所有变量。static pm.iterationData.isVariableScope(object: any):function → boolean:检查特定变量是否在范围内。
pm.cookies
pm.cookies: 阅读有关CookieList的更多信息
该cookies对象包含与请求域相关联的cookie列表。
pm.cookies.has(cookieName:String):Function → Boolean
检查请求的域是否存在特定的cookie(以其名称寻址)。pm.cookies.get(cookieName:String):Function → String
获取特定cookie的值。pm.cookies.toObject:Function → Object
以对象的形式获取所有cookie及其值的副本。返回的cookie是为请求的域和路径定义的cookie。
pm.cookies.jar
pm.cookies.jar():Function → Object
访问Cookie罐对象。jar.set(URL:String, cookie name:String, cookie value:String, callback(error, cookie)):Function → Object
使用Cookie名称和值设置Cookie。也可以通过在此函数中将cookie值与cookie名称相关联来直接设置cookie。jar.set(URL:String, { name:String, value:String, httpOnly:Bool }, callback(error, cookie)):Function → Object
使用PostmanCookie或其兼容对象设置cookie。jar.get(URL:String, token:String, callback (error, value)):Function → Object
从Cookie罐获取Cookie。jar.getAll(URL:String, callback (error, cookies)):Function → Object
从cookie罐中获取所有cookie。jar.unset(URL:String, token:String, callback(error)):Function → Object
取消设置Cookie。jar.clear(URL:String, callback (error)):Function → Object
清除饼干罐中的所有饼干。
pm.test
pm.test(testName:String, specFunction:Function):Function
您可以使用此功能在Pre-request Script或Tests沙箱中编写测试规范。在此函数中编写测试可以使您准确地命名测试,并且即使该函数内部存在错误,该函数也可以确保脚本的其余部分不会被阻塞。
在下面的示例测试中,我们正在检查关于响应的所有内容对我们来说都是有效的。
pm.test("response should be okay to process", function () {pm.response.to.not.be.error;pm.response.to.have.jsonBody('');pm.response.to.not.have.jsonBody('error');});done可以将 可选的回调添加到中pm.test,以测试异步功能。
pm.test('async test', function (done) {setTimeout(() => {pm.expect(pm.response.code).to.equal(200);done();}, 1500);});pm.test.index():Function → Number
从特定位置获取总数测试。
期望值
pm.expect(assertion:*):Function → Assertion
pm.expect是一个通用的断言函数。这是ChaiJS期望的BDD库的基础。使用该库,可以很容易地编写语法易读的测试。
此功能对于处理来自response或的数据断言很有用variables。有关使用的断言测试示例pm.expect,请查看断言库示例
测试脚本中可用的响应声明API
pm.response.to.have.status(code:Number)pm.response.to.have.status(reason:String)pm.response.to.have.header(key:String)pm.response.to.have.header(key:String, optionalValue:String)pm.response.to.have.body()pm.response.to.have.body(optionalValue:String)pm.response.to.have.body(optionalValue:RegExp)pm.response.to.have.jsonBody()pm.response.to.have.jsonBody(optionalExpectEqual:Object)pm.response.to.have.jsonBody(optionalExpectPath:String)pm.response.to.have.jsonBody(optionalExpectPath:String, optionalValue:*)pm.response.to.have.jsonSchema(schema:Object)pm.response.to.have.jsonSchema(schema:Object, ajvOptions:Object)
pm.to.be. *
通过pm.response.to.be对象内部的属性,您可以轻松地声明一组预定义规则。
pm.response.to.be.info
检查1XX状态码pm.response.to.be.success
检查2XX状态码pm.response.to.be.redirection
检查3XX状态码pm.response.to.be.clientError
检查4XX状态码pm.response.to.be.serverError
检查5XXpm.response.to.be.error
检查4XX或5XXpm.response.to.be.ok
状态码必须为200pm.response.to.be.accepted
状态码必须为202pm.response.to.be.badRequest
状态码必须为400pm.response.to.be.unauthorized
状态码必须为401pm.response.to.be.forbidden
状态码403pm.response.to.be.notFound
检查响应的状态码为404pm.response.to.be.rateLimited
检查响应状态码是否为429