一、背景
jsonpath 在處理 json 格式的數(shù)據(jù)方面是無敵的存在,前邊我也篇關(guān)于 jsonpath 介紹的文章 Json 數(shù)據(jù)提取神器 jsonpath ,今天介紹 jsonpath 在 Postman 腳本中的應(yīng)用
二、準(zhǔn)備JSONPath腳本
Postman 的腳本是 JavaScript 語言,因此需要準(zhǔn)備JS版本的JSONPath
1. JSONPath 源碼
JSONPath Github官網(wǎng)
說明:
- Github官網(wǎng)提供的JS語言的 JSONPath 版本 >= v0.12.0
- npm 官網(wǎng)提供的 package 如下:
JSONPath npm package(v0.8.0~v0.11.2)
jsonpath-plus npm package(>= v0.12.0)
npm安裝指定版本的JSONPathnpm i JSONPath@0.8.0
如果沒有nodejs環(huán)境,訪問下列地址下載源碼到本地
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.
*/
function jsonPath(obj, expr, arg) {
var P = {
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);
else if (loc === "*")
P.walk(loc, x, val, path, function(m,l,x,v,p) { P.trace(m+";"+x,v,p); });
else if (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); });
}
else if (/,/.test(loc)) { // [name1,name2,...]
for (var s=loc.split(/'?,'?/),i=0,n=s.length; i<n; i++)
P.trace(s[i]+";"+x, val, path);
}
else if (/^\(.*?\)$/.test(loc)) // [(expr)]
P.trace(P.eval(loc, val, path.substr(path.lastIndexOf(";")+1))+";"+x, val, path);
else if (/^\?\(.*?\)$/.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); });
else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) // [start:end:step] phyton slice syntax
P.slice(loc, x, val, path);
}
else
P.store(path, val);
},
walk: function(loc, expr, val, path, f) {
if (val instanceof Array) {
for (var i=0,n=val.length; i<n; i++)
if (i in val)
f(i,loc,expr,val,path);
}
else if (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 instanceof Array) {
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) { throw new SyntaxError("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, "$");
return P.result.length ? P.result : false;
}
}
三、Postman腳本拓展知識(shí)
1. 腳本的作用域
在 Postman 中有6處可以寫腳本的地方,分別是:Collection 的 Pre-request Script和Tests,F(xiàn)older 的 Pre-request Script和Tests,Request 的 Pre-request Script和Tests
它們各自的作用域如下:
- Collection中的腳本,僅作用于當(dāng)前集合(包括集合下的Folder)里的所有request,一般是項(xiàng)目維度的通用腳本放在這里;
- Folder中的腳本,僅作用于當(dāng)前文件夾下的所有request,一般是功能模塊維度的通用腳本放在這里;
- Request中的腳本,僅作用于當(dāng)前request
注意:上述6處腳本執(zhí)行時(shí)都是各自獨(dú)立的
- 如在Collection的Pre-request Script中定義變量和方法,在其他處的腳本內(nèi)是不可以直接使用的;
- 可以通過postman內(nèi)置變量傳遞變量或方法,如:在Collection的Pre-request Script中設(shè)置集合變量 pm.collectionVariables.set(“key”,“value”),在后邊其他腳本處可通過 pm.collectionVariables.get(“key”) 獲取并使用
2. 腳本執(zhí)行順序
腳本的執(zhí)行順序:
Collection Pre-request Script > Folder Pre-request Script > Request Pre-request Script > Collection Tests > Folder Tests > Request Tests
3. eval() 函數(shù)介紹
使用eval()函數(shù)執(zhí)行字符串類型的代碼
JavaScript中的eval()
函數(shù)
-
eval(string)
函數(shù)計(jì)算 JavaScript 字符串,并把它作為腳本代碼來執(zhí)行; - 如果參數(shù)是一個(gè)表達(dá)式,
eval()
函數(shù)將執(zhí)行表達(dá)式。如果參數(shù)是Javascript語句,eval()
將字符串轉(zhuǎn)化為 js 代碼并執(zhí)行; - 無法解釋執(zhí)行
const
聲明的常量或函數(shù)代碼,var聲明的可以執(zhí)行;
4. Postman內(nèi)置變量存放代碼塊
在使用Postman進(jìn)行接口測試時(shí)對(duì)于一些通用的腳本代碼塊,如果直接在腳本代碼里使用,由于腳本作用域及執(zhí)行順序的關(guān)系,會(huì)使腳本冗余難以閱讀及維護(hù)。
如何將通用代碼塊封裝成通用的方法,然后在需要的時(shí)候直接調(diào)用呢?
其實(shí)方法比較簡單,就是利用Postman內(nèi)置變量來存放代碼塊字符串,然后使用eval()函數(shù)解析并執(zhí)行代碼。接下來舉個(gè)栗子!
(1)定義變量存放代碼塊
在集合的Pre-request Script定義獲取格式化日期的函數(shù) dateFormat 下圖中的 dateFormat 代碼片段可到這里獲取:https://www.cnblogs.com/edda/p/14588184.html
說明:
Postman中有多種變量類型
- 按作用域劃分:Global變量、Environment變量、Collection變量、數(shù)據(jù)變量、本地變量
- Global變量:作用于當(dāng)前Workspace下的所有Collections,且在所有環(huán)境下生效;
- Environment變量:作用于當(dāng)前Workspace下的所有Collections,但僅在當(dāng)前環(huán)境生效;
- Collection變量:作用于當(dāng)前Collection,且在所有環(huán)境下生效;
- 數(shù)據(jù)變量:僅作用于當(dāng)前運(yùn)行的Collection或Folder(取值與迭代次數(shù)有關(guān))
- 本地變量:作用范圍與設(shè)置的位置有關(guān),如在集合腳本中則作用于集合下的所有Folder及Request
不同變量的權(quán)重
- 全局變量 < 集合變量 < 自定義環(huán)境變量 < 數(shù)據(jù)變量 < 本地變量
- 在請(qǐng)求構(gòu)造器中通過{{變量名}}取值時(shí),變量名相同時(shí),優(yōu)先取權(quán)重高的變量
(2)使用eval()函數(shù)執(zhí)行代碼
先通過 Postman 內(nèi)置變量獲取到 代碼塊字符串,然后通過eval()函數(shù)解釋為可執(zhí)行的代碼,示例如下:
四、Postman中使用JSONPath
在 Postman 腳本擴(kuò)展知識(shí) 章節(jié)已經(jīng)介紹過如何封裝公共方法,這里直接上圖。
說明:
- jsonpath 代碼可以存到Global變量中,這樣在所有集合及所有環(huán)境下都可調(diào)用
1. JSONPath代碼存放到Global變量
存放到變量里的代碼塊,建議壓縮一下 js在線壓縮工具
2. 使用JSONPath代碼
jsonpath語法規(guī)則可以參考:https://goessner.net/articles/JsonPath/
jsonpath語法在線測試工具推薦:http://jsonpath.com/
五、最后
薦一篇文章:Use Node packages not bundled into Postman’s sandbox
說明:
這篇文章也提供了在Postman腳本中使用外部腳本的方法,大致思路是:文章來源:http://www.zghlxwxcb.cn/news/detail-498635.html
- 啟動(dòng)一個(gè)Nodejs服務(wù),提供一個(gè)接口獲取指定的 packages
- 在Postman腳本使用 pm.sendRequest 方法調(diào)用這個(gè)接口,獲取js文件內(nèi)容
- 將獲取到的js代碼存放到Postman的Globals變量中(下次再訪問時(shí)就不用從接口獲取了)
- 然后使用eval()函數(shù)執(zhí)行代碼
思路可借鑒,但是我不太推薦這種方式,原因是nodejs環(huán)境里并不是所有packages通過這個(gè)接口返回的代碼,都能正常在Postman里工作,甚至請(qǐng)求某些package時(shí)接口還報(bào)錯(cuò)文章來源地址http://www.zghlxwxcb.cn/news/detail-498635.html
到了這里,關(guān)于Postman 腳本中使用jsonpath提取數(shù)據(jù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!