要想实现接口的自动化测试,需要以下几个步骤:
自动登录
首先点击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.comschema格式的约束文件,值得推荐的地方就是对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:Number
pm.response.reason():Function → String
pm.response.headers:HeaderList
pm.response.responseTime:Number
pm.response.text():Function → String
pm.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