json格式校验并显示错误_使用postman做自动化接口校验

要想实现接口的自动化测试,需要以下几个步骤:

自动登录

首先点击postman左上角的new按钮,创建一个collection,在pre-request-scripts标签下,给整个collection创建一个公用规则

642632d09b913ad15ff0ca340fb396fc.png

05a1e7575d030d5b6e34be0a3f709981.png

编写登录脚本

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"]);  });    
}

f064b84d663d44908af9d7b86b1577c6.png

yapi,去哪网出的开源的可视化接口管理平台,推荐部署到公司服务器,也可以直接使用官方的。

YApi-高效、易用、功能强大的可视化接口管理平台​yapi.demo.qunar.com

63442d5b4ad59ac8fe8fead86b19590b.png

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"]
}
开放Api​hellosean1025.github.io

获取接口的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});
编写测试入门-带有示例​documenter.getpostman.com

使用变量作为请求参数

(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}}
}

9c759783ebb8c867c0bb3d4f7c7029ed.png

在body里面获取变量注意事项

pm.collectionVariables.set("ids", [1,2,3]);
//在body里面需要这样写
{"ids":{{ids}}
}

自动化批量测试

9e4ed4f4d80a1e178daf384df09b6e20.png

17b6a312358ffb01f95c0bfbbce6ef41.png

查看格式报错

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

f419fc9c627a8320a6b68d559356d449.png

其他的集合测试用例

在编辑集合的弹窗里面,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 ScriptTests沙箱中编写测试规范。在此函数中编写测试可以使您准确地命名测试,并且即使该函数内部存在错误,该函数也可以确保脚本的其余部分不会被阻塞。

在下面的示例测试中,我们正在检查关于响应的所有内容对我们来说都是有效的。

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
    检查5XX
  • pm.response.to.be.error
    检查4XX或5XX
  • pm.response.to.be.ok
    状态码必须为200
  • pm.response.to.be.accepted
    状态码必须为202
  • pm.response.to.be.badRequest
    状态码必须为400
  • pm.response.to.be.unauthorized
    状态码必须为401
  • pm.response.to.be.forbidden
    状态码403
  • pm.response.to.be.notFound
    检查响应的状态码为404
  • pm.response.to.be.rateLimited
    检查响应状态码是否为429

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/409675.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

powerbuilder提示不是下拉窗口_为什么过去状态管理不是问题?

2-tier 架构远古时期&#xff0c;状态是完全由数据库管理的。数据库提供的连接是有状态的&#xff0c;打开页面的时候开连接&#xff0c;页面上的改动直接提交到当前的数据库连接。数据库连接的状态就是页面状态。3-tier 架构后来因为互联网类型的应用的发展&#xff0c;数据库…

kali字典_kali黑客系统wpscan工具扫描wordpress漏洞入侵攻击测试教程

WPScan是Kali Linux默认自带的一款漏洞扫描工具&#xff0c;它采用Ruby编写&#xff0c;能够扫描WordPress网站中的多种安全漏洞&#xff0c;其中包括主题漏洞、插件漏洞和WordPress本身的漏洞。最新版本WPScan的数据库中包含超过18000种插件漏洞和2600种主题漏洞&#xff0c;并…

mysql df_MySQL主从复制实战

什么是主从复制使用两个或两个以上的数据库&#xff0c;一部分数据库当做主数据库&#xff0c;而另一部分数据库当做从数据库。系统在主数据库中进行写操作&#xff0c;从数据库记录在主库上所有的写操作&#xff0c;使得主从数据库的数据保持一致。一旦主数据库出现问题时&…

python logistic回归_logistic回归介绍与源码分析

1. 介绍&#xff08;由线性模型引出logistic回归&#xff09;首先介绍一下什么是线性模型呢&#xff1f;线性模型的定义如下&#xff1a;给定 个属性描述的样本 &#xff0c; 代表样本在第 个属性上的取值。线性模型的目的是学习一个函数&#xff0c;它可以通过属性的线性组合来…

Activity、BroadcastReceiver、Service共同工作的简单例子

? Activity 好像是應用程式的眼睛&#xff0c;提供與User 互動之窗。 ? BroadcastReceiver 好像是耳朵&#xff0c;接收來自各方的Intent。 ? Service 好像是手&#xff0c;提供符合Intent 意圖之服務。 10.2.1 操作情境&#xff1a; 1. 此程式一開始&#xff0c;畫面出現兩…

线程执行一半断了_有的线程它死了,于是它变成一道面试题

----本文首发于公众号&#xff0c;关注文末公众号阅读体验更佳有些线程它活着&#xff0c;但它躺在池中碌碌无为&#xff1b;有的线程它死了&#xff0c;于是它变成一道面试题。这次的文章&#xff0c;要从一次阿里的面试说起。我记得那天是周一&#xff0c;刚刚经历过周末过的…

C#中的扩展方法,Linq,IO和多线程的定义和实例

前段时间学C#的上转型&#xff0c;泛型&#xff0c;lambda表达式这些应用的理解很费劲。学过之后我多多的练习了几天&#xff0c;接下来继续复习C#的其他一些概念&#xff0c;说实在的这些知识点学过之后很容易忘&#xff0c;但是都是很重要的&#xff0c;所以发表在博客上没事…

准确率 召回率_吴恩达深度学习笔记(61)-训练调参中的准确率和召回率

单一数字评估指标(Single number evaluation metric)无论你是调整超参数&#xff0c;或者是尝试不同的学习算法&#xff0c;或者在搭建机器学习系统时尝试不同手段&#xff0c;你会发现&#xff0c;如果你有一个单实数评估指标&#xff0c;你的进展会快得多&#xff0c;它可以快…

探讨LoadRunner的并发用户和集合点

探讨LoadRunner的并发用户和集合点 近来跟踪一个项目&#xff0c;发现同事们在执行性能测试时&#xff0c;比较热衷于使用集合点&#xff0c;从概念上认为要得到并发用户就必须设置集合点&#xff0c;认为在执行一个压力测试脚本时&#xff0c;设置了集合点才算是有效的并发用…

spring gateway 鉴权_通过spring实现service变成controller,代码得到了简化

在网上发现了一个牛X的思路&#xff0c;在做restful的时候&#xff0c;如果业务改变&#xff0c;需要每次都修改controller&#xff0c;后来方便了&#xff0c;直接透传的方式&#xff0c;其实也比较麻烦&#xff0c;每次都要写controller。需求变了接口也发生了改变&#xff0…

java中return返回值_Java中return的用法

展开全部一、return语句总是用在方法中&#xff0c;有两个作用。一个是返回方法指定类型的值(这个值总62616964757a686964616fe59b9ee7ad9431333366306434是确定的)。一个是结束方法的执行(仅仅一个return语句)。二、实例1 。返回一个String。private String gets(){String s …

java 事件分发线程_深入浅出Java多线程(2)-Swing中的EDT(事件分发线程) [转载]...

本系列文章导航本文主要解决的问题是&#xff1a;如何使其Swing程序只能运行一个实例&#xff1f;抛开Swing&#xff0c; 我们的程序是通过java 命令行启动一个进程来执行的&#xff0c;该问题也就是说要保证这个进程的唯一性&#xff0c;当然如果能够访问系统的接口&#xff0…

java redis 分布式锁_使用Redis单实例实现分布式锁

一、前言在同一个jvm进程中时&#xff0c;可以使用JUC提供的一些锁来解决多个线程竞争同一个共享资源时候的线程安全问题&#xff0c;但是当多个不同机器上的不同jvm进程共同竞争同一个共享资源时候&#xff0c;juc包的锁就无能无力了&#xff0c;这时候就需要分布式锁了。常见…

设计一个按优先数调度算法实现处理器调度的程序_计算机中的程序都是怎么运行的,来深入了解一下吧...

在现代计算机操作系统中&#xff0c;总是会保持多道程序环境。一个作业被提交后&#xff0c;通常经过作业调度和进程调度后&#xff0c;才能获得处理机。有时为提高内存利用率&#xff0c;还会设置中程调度。那我们先来了解一下处理机调度的层次吧。高级调度&#xff0c;又称作…

mysql 查看锁_SQL-mysql锁等待与死锁

一 前言本篇是MYSQL高级进阶篇内容第二篇&#xff0c;学习本篇的基础是知识追寻者之前发布过的文章&#xff0c;尤其是《MYSQL架构入门篇》重中之重&#xff1b;《SQL-你真的了解什么SQL么&#xff1f;》《SQL-小白最佳入门sql查询一》《SQL-小白最佳入门sql查询二》《SQL- 多年…