在項目實踐中,遇到了這樣一個問題。用jmeter作http接口測試,需要的接口參數個數是不確定的。也就是說,在每次測試中,根據情況不同,可能頁面中的列表中所含的參數個數是不確定的,那么要提取的參數個數也是不確定的,可能是1個,也可能是2個或3個,甚至更多。
例如,返回的接口消息json消息可能如下
{
"data": {
"records": [{
"DEVICE_TYPE": 194,
"DEVICE_STATUS": 0,
"ORG_NAME": "**省",
"LONGITUDE": "0.000000",
"DEVICE_NAME": "測試1",
"DEVICE_ADDR": "",
"DEVICE_ID_INT": "13",
"HAVE_VIDEO": "true",
"OWNER": "-1",
"ORIGINAL_DEVICE_ID": "44000000011325******",
"PLATFORM_ID": "44000000052005******",
"ORG_CODE": "44",
"TYPE": "1",
"DEVICE_ID": "44000000011325******",
"LATITUDE": "0.000000"
}, {
"DEVICE_TYPE": 194,
"DEVICE_STATUS": 0,
"LONGITUDE": "0.000000",
"DEVICE_NAME": "測試2",
"DEVICE_ADDR": "",
"DEVICE_ID_INT": "10",
"HAVE_VIDEO": "true",
"OWNER": "1",
"ORIGINAL_DEVICE_ID": "44010000001320******",
"PLATFORM_ID": "44000000052005******",
"ORG_CODE": "4401",
"TYPE": "1",
"DEVICE_ID": "440100000013200******",
"LATITUDE": "0.000000"
}, {
"DEVICE_TYPE": 194,
"DEVICE_STATUS": 0,
"LONGITUDE": "0.000000",
"DEVICE_NAME": "測試3",
"DEVICE_ADDR": "",
"DEVICE_ID_INT": "11",
"HAVE_VIDEO": "true",
"OWNER": "1",
"ORIGINAL_DEVICE_ID": "44010000001320******",
"PLATFORM_ID": "44000000052005******",
"ORG_CODE": "4401",
"TYPE": "1",
"DEVICE_ID": "44010000001320******",
"LATITUDE": "0.000000"
}],
"count": 3,
"usetime": 0
}
}
說是可能,是因為存在多種不同的返回結果,上述json消息中返回的有3個設備信息,但也可能是1個,也可能是2個,或者是更多,具體的數值要根據頁面狀況。我們的任務是從返回的json消息中提取所有的設備ID號(DEVICE_ID)。
個人認為,這種初始環境的不確定性本來是自動化測試的大忌,會給腳本的成功運行帶來很大的風險,但在實際應用中,由於測試環境並非是個人獨占的,每次測試時,頁面配置的變化是可以理解的存在。為了提高腳本的健壯性,最好的辦法是每次根據實際頁面的返回值,提取其中的所有參數,然后拼接好,存jmeter的內部變量以供后續接口使用。要做好這一點,光用現成的jmeter工具,尤其是我們常用的json提取器(json extractor)肯定是無法做到了,至少做不到參數拼接后續處理。如果針對不同的場景,用if控制器來做區分,又會顯得太累贅。
作為一個世界級的以java為基礎的開源工具,肯定有其他的辦法,個人感覺,jmeter搭載了beanshell就好像robot framework搭載了evaluate,一下子世界寬廣了。作為一個半吊子,jmeter還沒搞透徹,java也沒用過,又要開始研究beanshell也是有點拼。只好求助萬能的度娘。網上提到了一種beanshell postprocessor結合fastjson庫的方法,可以做json的快速高效提取。
先把配置環境說一下,我用到的是jmeter5.0,fastjson用到的是1.2.47的版本,下載地址如下http://repo1.maven.org/maven2/com/alibaba/fastjson/1.2.47/,需要把下載下來的jar包放到jmeter的安裝路徑的lib/ext庫中,並且在jmeter test plan中引用這個jar包
在需要提取的頁面添加BeanShell后置處理器
script編寫如下:
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; // 獲取數據 //log.info("---something---"); String response = prev.getResponseDataAsString(); // 獲取Response //log.info("Respnse is " + response); JSONObject responseObj = JSON.parseObject(response); // 整個Response作為JSON對象 JSONObject resObj = responseObj.getJSONObject("data"); // 獲取某一部分對象。即,json串中{}的內容 //log.info("resObj is " + resObj); JSONArray listArray = resObj.getJSONArray("records"); // 獲取列表。即,json串中[]的內容 // 保存數據 // 1) 列表 //log.info("listArray is "+ listArray); //log.info("array[0] is "+ listArray.getJSONObject(0).getString("DEVICE_ID")); int len = listArray.size(); String[] temp = new String[len]; StringBuffer sBuffer = new StringBuffer(""); for(int i=0;i<len;i++){ temp[i]= listArray.getJSONObject(i).getString("DEVICE_ID"); sBuffer.append(temp[i]).append(","); // log.info("sbuffer---"+sBuffer); //vars.put("deviceId"+i, temp[i]);// 保存到JMeter變量中 //log.info("deviceIdAll===",deviceIdAll); } String keywordStr = sBuffer.deleteCharAt(sBuffer.length() - 1).toString(); vars.put("deviceId",keywordStr);
主要用到的API釋義如下:
1. 將json字符串反序列化成JSON對象
JSONObject com.alibaba.fastjson.JSON.parseObject(String text)
2.根據key 得到json中的json數組
JSONArray com.alibaba.fastjson.JSONObject.getJSONArray(String key)
3. 根據下標拿到json數組的json對象
JSONObject com.alibaba.fastjson.JSONArray.getJSONObject(int index)
4.. 根據key拿到json的字符串值
String com.alibaba.fastjson.JSONObject.getString(String key)
更詳細的fastjson的詳細API參考了這篇文章:https://www.cnblogs.com/qiaoyeye/p/7730288.html
總結一下,此次踩過的坑主要有如下:
1.字符串是定義好之后就不能變更的,屬於常量,和之前使用python的經驗不同,在java中對於字符串,是不能使用拼接操作的,要不斷寫字符串,得用StringBuffer類。網上找到了這段話:
當對字符串進行修改的時候,需要使用 StringBuffer 和 StringBuilder 類。
和 String 類不同的是,StringBuffer 和 StringBuilder 類的對象能夠被多次的修改,並且不產生新的未使用對象。
StringBuilder 類在 Java 5 中被提出,它和 StringBuffer 之間的最大不同在於 StringBuilder 的方法不是線程安全的(不能同步訪問)。
由於 StringBuilder 相較於 StringBuffer 有速度優勢,所以多數情況下建議使用 StringBuilder 類。然而在應用程序要求線程安全的情況下,則必須使用 StringBuffer 類。
2.運行時在控制台總是提示有這樣的錯誤"Jmeter ERROR o.a.j.u.BeanShellInterpreter: Error invoking bsh method",我一直在懷疑是fastjson這個第三方庫的使用有問題,最后發現是由於腳本中存在代碼錯誤導致的,至於錯誤的原因,自己一行一行地找,所以在腳本中我加了無數的log.info,不得不說,beanshell腳本缺乏IDLE的編碼環境,確實很不友好。
總之,通過這次的實踐,進一步擴充了自己的知識面,再一次體會到,邊走邊看,堅持往前走的魅力所在。不要想着准備好所有的必要條件再出發,要用事情來推動自己去創造條件,任何經歷都是成長。工作與生活皆如此!