一、背景
jsonpath 在处理 json 格式的数据方面是无敌的存在,前边我也篇关于 jsonpath 介绍的文章 Json 数据提取神器 jsonpath ,今天介绍 jsonpath 在 Postman 脚本中的应用
二、准备JSONPath脚本
Postman 的脚本是 JavaScript 语言,因此需要准备JS版本的JSONPath
1. JSONPath 源码
JSONPath Github官网
说明:
- Github官网提供的JS语言的 JSONPath 版本 >= v0.12.0
- npm 官网提供的 package 如下: JSONPath npm package(v0.8.0~v0.11.2) jsonpath-plus npm package(>= v0.12.0)
npm安装指定版本的JSONPath
npm i [email protected]
如果没有nodejs环境,访问下列地址下载源码到本地
js版本的 jsonpath package下载 (v0.8.0)
源码在JSONPath包的 lib/jsonpath.js
jsonpath.js源码:
/* JSONPath 0.8.0 - XPath for JSON
*
* Copyright (c) 2007 Stefan Goessner (goessner.net)
* Licensed under the MIT (MIT-LICENSE.txt) licence.
*/functionjsonPath(obj, expr, arg){varP={resultType: arg && arg.resultType ||"VALUE",result:[],normalize:function(expr){var subx =[];return expr.replace(/[\['](\??\(.*?\))[\]']/g,function($0,$1){return"[#"+(subx.push($1)-1)+"]";}).replace(/'?\.'?|\['?/g,";").replace(/;;;|;;/g,";..;").replace(/;$|'?\]|'$/g,"").replace(/#([0-9]+)/g,function($0,$1){return subx[$1];});},asPath:function(path){var x = path.split(";"), p ="$";for(var i=1,n=x.length; i<n; i++)
p +=/^[0-9*]+$/.test(x[i])?("["+x[i]+"]"):("['"+x[i]+"']");return p;},store:function(p, v){if(p)P.result[P.result.length]=P.resultType =="PATH"?P.asPath(p): v;return!!p;},trace:function(expr, val, path){if(expr){var x = expr.split(";"), loc = x.shift();
x = x.join(";");if(val && val.hasOwnProperty(loc))P.trace(x, val[loc], path +";"+ loc);elseif(loc ==="*")P.walk(loc, x, val, path,function(m,l,x,v,p){P.trace(m+";"+x,v,p);});elseif(loc ===".."){P.trace(x, val, path);P.walk(loc, x, val, path,function(m,l,x,v,p){typeof v[m]==="object"&&P.trace("..;"+x,v[m],p+";"+m);});}elseif(/,/.test(loc)){// [name1,name2,...]for(var s=loc.split(/'?,'?/),i=0,n=s.length; i<n; i++)P.trace(s[i]+";"+x, val, path);}elseif(/^\(.*?\)$/.test(loc))// [(expr)]P.trace(P.eval(loc, val, path.substr(path.lastIndexOf(";")+1))+";"+x, val, path);elseif(/^\?\(.*?\)$/.test(loc))// [?(expr)]P.walk(loc, x, val, path,function(m,l,x,v,p){if(P.eval(l.replace(/^\?\((.*?)\)$/,"$1"),v[m],m))P.trace(m+";"+x,v,p);});elseif(/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc))// [start:end:step] phyton slice syntaxP.slice(loc, x, val, path);}elseP.store(path, val);},walk:function(loc, expr, val, path, f){if(val instanceofArray){for(var i=0,n=val.length; i<n; i++)if(i in val)f(i,loc,expr,val,path);}elseif(typeof val ==="object"){for(var m in val)if(val.hasOwnProperty(m))f(m,loc,expr,val,path);}},slice:function(loc, expr, val, path){if(val instanceofArray){var len=val.length, start=0, end=len, step=1;
loc.replace(/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/g,function($0,$1,$2,$3){start=parseInt($1||start);end=parseInt($2||end);step=parseInt($3||step);});
start =(start <0)? Math.max(0,start+len): Math.min(len,start);
end =(end <0)? Math.max(0,end+len): Math.min(len,end);for(var i=start; i<end; i+=step)P.trace(i+";"+expr, val, path);}},eval:function(x, _v, _vname){try{return $ && _v &&eval(x.replace(/@/g,"_v"));}catch(e){thrownewSyntaxError("jsonPath: "+ e.message +": "+ x.replace(/@/g,"_v").replace(/\^/g,"_a"));}}};var $ = obj;if(expr && obj &&(P.resultType =="VALUE"||P.resultType =="PATH")){P.trace(P.normalize(expr).replace(/^\$;/,""), obj,"$");returnP.result.length ?P.result :false;}}
三、Postman脚本拓展知识
1. 脚本的作用域
在 Postman 中有6处可以写脚本的地方,分别是:Collection 的 Pre-request Script和Tests,Folder 的 Pre-request Script和Tests,Request 的 Pre-request Script和Tests
它们各自的作用域如下:
- Collection中的脚本,仅作用于当前集合(包括集合下的Folder)里的所有request,一般是项目维度的通用脚本放在这里;
- Folder中的脚本,仅作用于当前文件夹下的所有request,一般是功能模块维度的通用脚本放在这里;
- Request中的脚本,仅作用于当前request
注意:上述6处脚本执行时都是各自独立的
- 如在Collection的Pre-request Script中定义变量和方法,在其他处的脚本内是不可以直接使用的;
- 可以通过postman内置变量传递变量或方法,如:在Collection的Pre-request Script中设置集合变量 pm.collectionVariables.set(“key”,“value”),在后边其他脚本处可通过 pm.collectionVariables.get(“key”) 获取并使用
2. 脚本执行顺序
脚本的执行顺序:
Collection Pre-request Script > Folder Pre-request Script > Request Pre-request Script > Collection Tests > Folder Tests > Request Tests
3. eval() 函数介绍
使用eval()函数执行字符串类型的代码
JavaScript中的
eval()
函数
eval(string)
函数计算 JavaScript 字符串,并把它作为脚本代码来执行;- 如果参数是一个表达式,
eval()
函数将执行表达式。如果参数是Javascript语句,eval()
将字符串转化为 js 代码并执行; - 无法解释执行
const
声明的常量或函数代码,var声明的可以执行;
4. Postman内置变量存放代码块
在使用Postman进行接口测试时对于一些通用的脚本代码块,如果直接在脚本代码里使用,由于脚本作用域及执行顺序的关系,会使脚本冗余难以阅读及维护。
如何将通用代码块封装成通用的方法,然后在需要的时候直接调用呢?
其实方法比较简单,就是利用Postman内置变量来存放代码块字符串,然后使用eval()函数解析并执行代码。接下来举个栗子!
(1)定义变量存放代码块
在集合的Pre-request Script定义获取格式化日期的函数 dateFormat 下图中的 dateFormat 代码片段可到这里获取:https://www.cnblogs.com/edda/p/14588184.html
说明:
Postman中有多种变量类型
- 按作用域划分:Global变量、Environment变量、Collection变量、数据变量、本地变量
- Global变量:作用于当前Workspace下的所有Collections,且在所有环境下生效;
- Environment变量:作用于当前Workspace下的所有Collections,但仅在当前环境生效;
- Collection变量:作用于当前Collection,且在所有环境下生效;
- 数据变量:仅作用于当前运行的Collection或Folder(取值与迭代次数有关)
- 本地变量:作用范围与设置的位置有关,如在集合脚本中则作用于集合下的所有Folder及Request
不同变量的权重
- 全局变量 < 集合变量 < 自定义环境变量 < 数据变量 < 本地变量
- 在请求构造器中通过{{变量名}}取值时,变量名相同时,优先取权重高的变量
(2)使用eval()函数执行代码
先通过 Postman 内置变量获取到 代码块字符串,然后通过eval()函数解释为可执行的代码,示例如下:
四、Postman中使用JSONPath
在 Postman 脚本扩展知识 章节已经介绍过如何封装公共方法,这里直接上图。
说明:
- jsonpath 代码可以存到Global变量中,这样在所有集合及所有环境下都可调用
1. JSONPath代码存放到Global变量
存放到变量里的代码块,建议压缩一下 js在线压缩工具
2. 使用JSONPath代码
jsonpath语法规则可以参考:https://goessner.net/articles/JsonPath/
jsonpath语法在线测试工具推荐:http://jsonpath.com/
五、最后
荐一篇文章:Use Node packages not bundled into Postman’s sandbox
说明:
这篇文章也提供了在Postman脚本中使用外部脚本的方法,大致思路是:
- 启动一个Nodejs服务,提供一个接口获取指定的 packages
- 在Postman脚本使用 pm.sendRequest 方法调用这个接口,获取js文件内容
- 将获取到的js代码存放到Postman的Globals变量中(下次再访问时就不用从接口获取了)
- 然后使用eval()函数执行代码
思路可借鉴,但是我不太推荐这种方式,原因是nodejs环境里并不是所有packages通过这个接口返回的代码,都能正常在Postman里工作,甚至请求某些package时接口还报错
版权归原作者 小青龍 所有, 如有侵权,请联系我们删除。