1. 程式人生 > >Jmeter介面自動化例項(使用Beanshell儲存csv檔案、csv引數化、setUp執行緒組)

Jmeter介面自動化例項(使用Beanshell儲存csv檔案、csv引數化、setUp執行緒組)

很久沒更新部落格了,荒廢了很久了,今天更新一下部落格,主要記錄一下子最近遇到的問題和解決方法:blonde_woman:

這篇文章主要記錄的是jmeter批量跑介面中遇到的各種疑難,主要涉及到的問題如下

  1. 執行的介面有多個(>=2)其中有一個前提是必須登入才能進行其他介面的操作,但是登入不想每次都執行,該怎麼解決呢,請往下看~
  2. 批量執行介面的過程中,需要不同的引數執行介面,使用到了csv引數化
  3. 介面結束之後,需要對響應結果中的一部分資訊保留進行資料對比

進入正題,先來解決第一個問題,登入介面只需要執行一次即可,然後其他介面可以使用登入響應結果中的token值進行介面操作。這裡jmeter提供了setUp執行緒可以解決這個問題。

首先在jmeter計劃中新增一個執行緒setUp,把登入介面放置到setUp執行緒中,然後使用json提取器獲取到token資訊,並把token資訊儲存為jmeter變數,如圖

登入的響應結果資訊如下

{
    "access_token":"dc1dcb1f-725e-4b17-9f47-e1d97477ba11",
    "token_type":"bearer",
    "refresh_token":"307cee12-973e-44af-8022-63949b2c3bd5",
    "expires_in":899,
    "scope":"READ WRITE"
}

這裡主要使用json提取器來獲取token的變數資訊

根據響應結果,使用json提取器,主要用$.access_token提取變數。

然後使用Beanshell後置處理器,將變數儲存為jmeter系統變數,程式碼如下

${__setProperty(all_token,${access_token},false)}

如圖

跨執行緒的其他執行緒組怎麼使用這個變數access_token呢,可以使用http資訊頭管理器來實現,在http資訊頭管理器中,新增Authorization來實現,如圖

Authorization   Bearer ${__property(all_token,,)}

至此第一個問題已經解決了,那麼接下來就是第二個介面的引數化操作了。

這裡主要使用了csv進行引數化

csv文字引數資訊如圖

引數化文字已經準備好了,接下來就是在jmeter中新增csv資料檔案設定,如圖

說明:

  1. 檔名稱:引數化的csv檔案

  2. 檔案編碼:預設可以不填,這裡因為有中文,所以使用gb2312,可以根據實際情況設定utf-8或其他

  3. 變數名稱:這裡設定的變數名稱在介面中會使用這個變數資訊,所以一定要慎重

如圖上所標識,這裡的變數名稱必須一致。

到這裡,已經完成了csv的引數化,那麼我們如果獲取響應的結果呢?

先來看一下相應的結果的結構是什麼吧~

[
    {
        "properties":{
            "cal_name":"雲耳",
            "e_type":"food",
            "end_index":12,
            "food_id":8457,
            "kcal_unit_weight":37.95,
            "name":"雲耳",
            "start_index":10,
            "time_stamp":1566544101
        },
        "sub_properties":{
            "grams":30,
            "is_default":true,
            "quantifier_id":57,
            "quantity":1,
            "unit":"朵"
        },
        "type":"Entity"
    },
    {
        "properties":{
            "cal_name":"黑木耳",
            "e_type":"food",
            "end_index":9,
            "food_id":8456,
            "kcal_unit_weight":37.95,
            "name":"黑木耳",
            "start_index":6,
            "time_stamp":1566544101
        },
        "sub_properties":{
            "grams":30,
            "is_default":true,
            "quantifier_id":57,
            "quantity":1,
            "unit":"朵"
        },
        "type":"Entity"
    },
    {
        "properties":{
            "cal_name":"木耳",
            "e_type":"food",
            "end_index":2,
            "food_id":5593,
            "kcal_unit_weight":37.95,
            "name":"木耳",
            "start_index":0,
            "time_stamp":1566544101
        },
        "sub_properties":{
            "grams":30,
            "is_default":true,
            "quantifier_id":57,
            "quantity":1,
            "unit":"朵"
        },
        "type":"Entity"
    }
]

當然還可以使用json提取器,來獲取變數資訊的,使用$[*].properties.cal_name;$[*].properties.name,兩個變數之前使用;分開,如圖所示

根據之前的使用BeanShell斷言判斷請求返回的Json相應結果(不同json格式整理)瞭解到可以使用BeanShell來獲取響應結果的變數。

好了,那麼接下來就是如何保儲存響應結果中需要的資訊到csv文字中了。

jmeter中beanshell提供了寫入csv檔案的方法,主要程式碼如下

//儲存的本地檔案
FileWriter fo = new FileWriter("E:\\test\\result_jm.csv",true);
BufferedWriter out = new BufferedWriter(fo);
//需要儲存的欄位資訊
out.write(vars.get("cal")+":"+vars.get("name")+",");
//每個資訊完成之後需要換行
out.write(System.getProperty("line.separator"));

out.close();
fo.close();

這裡想實現的主要是:對於響應結果非空的資料則儲存響應結果到檔案1,而對於響應結果為空,則只需要儲存輸入的引數資訊到檔案2,以便後期對比確認介面資料準確度。

完整程式碼如下

import org.json.*;
import org.json.JSONObject;
import org.json.JSONAarry;
//設定檔案編碼
prev.setDataEncoding("UTF-8");
int i=0;
try{
    log.info("響應結果中的cal_name是"+vars.get("cal"));
    //獲取json提取器中的變數cal
    //String cal_test = vars.get("cal");
    String response_data = prev.getResponseDataAsString();//獲取請求返回值,此處獲取到String型別;
    //JSONObject data_obj = new JSONObject(response_data);//將string型別的返回值構建成JSONObject物件

    //JSONArray data_array = response_data.getJSONArray[0];//返回結果是陣列
    JSONArray data_array = new JSONArray(response_data);
    
    int len = data_array.length();//獲取data陣列的長度
    String strlen = Integer.toString(len);
    log.info("響應結果字串長度是"+strlen);
    
    String str_array = data_array.toString();
    log.info("響應結果字串是:"+str_array);
    
    
    
    //cal_test  str_array == null ;cal_test.length() !=null;str_array.equals(0)
    if(len==0){
        log.info("*****************食物匹配失敗********************");
        //如果響應結果為空,則只儲存food名字到本地檔案
        FileWriter fos = new FileWriter("E:\\test\\HB\\food_result2_jm.csv",true);
        BufferedWriter outs = new BufferedWriter(fos);
        outs.write(vars.get("food")+",");
        log.info("原來的食譜名稱是:"+ vars.get("food"));
        outs.write(System.getProperty("line.separator"));

        outs.close();
        fos.close();
        
    }else{
        
        log.info("*************響應結果中獲取食物cal和name****************");
        
        for(i=0;i<len;i++){
            //返回陣列
            JSONObject object = data_array.getJSONObject(i);
            //只獲取響應結果中第一個properites的資訊,需要取得多個properties,則可以使用for迴圈
            JSONObject temp_properties = (JSONObject)object.getJSONObject("properties");
            //只獲取響應結果中properties中的calname值
            cal_name_string = temp_properties.getString("cal_name");
            log.info("Beanshell 後置處理器的提取的響應cal_name響應結果是:"+ cal_name_string);
            //儲存響應結果中的cal_name變數
            vars.put("cal_name_string",cal_name_string);
            
            name_string = temp_properties.getString("name");
            log.info("Beanshell 後置處理器的提取的響應name_string響應結果是:"+ name_string);
            //儲存響應結果中的cal_name變數
            vars.put("name_string",name_string);

            log.info("*************食物匹配有結果****************");
            //儲存的本地檔案,儲存響應結果非空的資料
            FileWriter fo = new FileWriter("E:\\test\\HB\\food_result1_jm.csv",true);
            BufferedWriter out = new BufferedWriter(fo);
            out.write(vars.get("name_string")+":"+vars.get("cal_name_string")+":"+vars.get("food")+",");

            log.info("響應結果中食物名稱是:"+ vars.get("cal_name_string"));
            log.info("響應結果中食物名稱是:"+ vars.get("name_string"));
            log.info("原來的食譜名稱是:"+ vars.get("food"));
            out.write(System.getProperty("line.separator"));

            out.close();
            fo.close();
        }
        
    }


    //JSONObject object = data_array.getJSONObject(0);
    //log.info(object);
    //String cal_test = object.getString("cal_name");
    
    
}
catch(Throwable ex){
    log.error("Failed in Beanshell",ex);
    throw ex;
//  //如果響應結果為空,則只儲存food名字到本地檔案
//  FileWriter fos = new FileWriter("E:\\test\\HB\\food_result2_jm.csv",true);
//  BufferedWriter outs = new BufferedWriter(fos);
//  outs.write(vars.get("food")+",");
//  log.info(vars.get("food"));
//  outs.write(System.getProperty("line.separator"));
//
//  outs.close();
//  fos.close();

    
}

這裡使用到了json包,提供一個下載地址:https://repo1.maven.org/maven2/org/json/json/20190722/

ok,到這裡jmeter一個完整的流程就結束了,這裡有部分jmeter的結果資訊,如下

2019-08-23 15:08:28,064 INFO o.a.j.t.JMeterThread: Thread is done: chatbot 1-2628
2019-08-23 15:08:28,064 INFO o.a.j.t.JMeterThread: Thread finished: chatbot 1-2628
2019-08-23 15:08:28,065 INFO o.a.j.u.BeanShellTestElement: 響應結果字串長度是1
2019-08-23 15:08:28,065 INFO o.a.j.u.BeanShellTestElement: 響應結果字串是:[{"sub_properties":{"unit":"杯","quantifier_id":32,"quantity":1,"grams":250,"is_default":true},"type":"Entity","properties":{"start_index":0,"time_stamp":1566544108,"cal_name":"野菊","name":"野菊","end_index":2,"kcal_unit_weight":46.8,"food_id":5559,"e_type":"food"}}]
2019-08-23 15:08:28,065 INFO o.a.j.u.BeanShellTestElement: *************響應結果中獲取食物cal和name****************
2019-08-23 15:08:28,065 INFO o.a.j.u.BeanShellTestElement: Beanshell 後置處理器的提取的響應cal_name響應結果是:野菊
2019-08-23 15:08:28,065 INFO o.a.j.u.BeanShellTestElement: Beanshell 後置處理器的提取的響應name_string響應結果是:野菊
2019-08-23 15:08:28,065 INFO o.a.j.u.BeanShellTestElement: *************食物匹配有結果****************
2019-08-23 15:08:28,067 INFO o.a.j.u.BeanShellTestElement: 響應結果中食物名稱是:野菊
2019-08-23 15:08:28,067 INFO o.a.j.u.BeanShellTestElement: 響應結果中食物名稱是:野菊
2019-08-23 15:08:28,067 INFO o.a.j.u.BeanShellTestElement: 原來的食譜名稱是:野菊(鮮)
...
2019-08-23 15:08:30,407 INFO o.a.j.t.JMeterThread: Thread is done: chatbot 1-2690
2019-08-23 15:08:30,407 INFO o.a.j.t.JMeterThread: Thread finished: chatbot 1-2690
2019-08-23 15:08:30,522 INFO o.a.j.u.BeanShellTestElement: 響應結果中的cal_name是竹參
2019-08-23 15:08:30,524 INFO o.a.j.u.BeanShellTestElement: 響應結果字串長度是3
2019-08-23 15:08:30,524 INFO o.a.j.u.BeanShellTestElement: 響應結果字串是:[{"sub_properties":{"unit":"份","quantifier_id":18,"quantity":1,"grams":200,"is_default":true},"type":"Entity","properties":{"start_index":8,"time_stamp":1566544110,"cal_name":"竹參","name":"竹參","end_index":10,"kcal_unit_weight":155,"food_id":12628,"e_type":"food"}},{"sub_properties":{"unit":"份","quantifier_id":18,"quantity":1,"grams":200,"is_default":true},"type":"Entity","properties":{"start_index":5,"time_stamp":1566544110,"cal_name":"幹竹笙","name":"竹笙","end_index":7,"kcal_unit_weight":312.116,"food_id":10653,"e_type":"food"}},{"sub_properties":{"unit":"片","quantifier_id":34,"quantity":1,"grams":7,"is_default":true},"type":"Entity","properties":{"start_index":0,"time_stamp":1566544110,"cal_name":"竹蓀","name":"竹蓀","end_index":2,"kcal_unit_weight":155,"food_id":5607,"e_type":"food"}}]
2019-08-23 15:08:30,524 INFO o.a.j.u.BeanShellTestElement: *************響應結果中獲取食物cal和name****************
2019-08-23 15:08:30,524 INFO o.a.j.u.BeanShellTestElement: Beanshell 後置處理器的提取的響應cal_name響應結果是:竹參
2019-08-23 15:08:30,524 INFO o.a.j.u.BeanShellTestElement: Beanshell 後置處理器的提取的響應name_string響應結果是:竹參
2019-08-23 15:08:30,524 INFO o.a.j.u.BeanShellTestElement: *************食物匹配有結果****************
2019-08-23 15:08:30,526 INFO o.a.j.u.BeanShellTestElement: 響應結果中食物名稱是:竹參
2019-08-23 15:08:30,526 INFO o.a.j.u.BeanShellTestElement: 響應結果中食物名稱是:竹參
2019-08-23 15:08:30,526 INFO o.a.j.u.BeanShellTestElement: 原來的食譜名稱是:竹蓀(幹)竹笙、竹參
2019-08-23 15:08:30,526 INFO o.a.j.u.BeanShellTestElement: Beanshell 後置處理器的提取的響應cal_name響應結果是:幹竹笙
2019-08-23 15:08:30,526 INFO o.a.j.u.BeanShellTestElement: Beanshell 後置處理器的提取的響應name_string響應結果是:竹笙
2019-08-23 15:08:30,526 INFO o.a.j.u.BeanShellTestElement: *************食物匹配有結果****************
2019-08-23 15:08:30,527 INFO o.a.j.u.BeanShellTestElement: 響應結果中食物名稱是:幹竹笙
2019-08-23 15:08:30,527 INFO o.a.j.u.BeanShellTestElement: 響應結果中食物名稱是:竹笙
2019-08-23 15:08:30,527 INFO o.a.j.u.BeanShellTestElement: 原來的食譜名稱是:竹蓀(幹)竹笙、竹參
2019-08-23 15:08:30,527 INFO o.a.j.u.BeanShellTestElement: Beanshell 後置處理器的提取的響應cal_name響應結果是:竹蓀
2019-08-23 15:08:30,527 INFO o.a.j.u.BeanShellTestElement: Beanshell 後置處理器的提取的響應name_string響應結果是:竹蓀
2019-08-23 15:08:30,527 INFO o.a.j.u.BeanShellTestElement: *************食物匹配有結果****************
2019-08-23 15:08:30,528 INFO o.a.j.u.BeanShellTestElement: 響應結果中食物名稱是:竹蓀
2019-08-23 15:08:30,528 INFO o.a.j.u.BeanShellTestElement: 響應結果中食物名稱是:竹蓀
2019-08-23 15:08:30,528 INFO o.a.j.u.BeanShellTestElement: 原來的食譜名稱是:竹蓀(幹)竹笙、竹參
2019-08-23 15:08:30,528 INFO o.a.j.t.JMeterThread: Thread is done: chatbot 1-2685
2019-08-23 15:08:30,528 INFO o.a.j.t.JMeterThread: Thread finished: chatbot 1-2685
2019-08-23 15:08:30,529 INFO o.a.j.e.StandardJMeterEngine: Notifying test listeners of end of test
2019-08-23 15:08:30,529 INFO o.a.j.s.FileServer: Close: E:\test\HB\qa.csv
2019-08-23 15:08:30,529 INFO o.a.j.s.FileServer: Close: E:\test\HB\food_jm.csv
2019-08-23 15:08:30,529 INFO o.a.j.g.u.JMeterMenuBar: setRunning(false, *local*)

總結:以上就是jmeter介面測試所遇到的問題以及如何解決的~,這裡還有一點小問題,因為引數化的時候,是中文資訊,所以開始的時候一直都是亂碼,這裡說一下有幾個辦法,給大家一個參考。

第一個方法:修改jmeter.properties檔案中的編碼格式為utf-8sampleresult.default.encoding=UTF-8

第二個方法,介面資訊中設定編碼格式為utf-8,如圖

第三個方法:在beanshell中設定編碼格式為utf-8,//設定檔案編碼
prev.setDataEncoding("UTF-8");

還有可能不是編碼格式的問題,而是字型支援的原因,可以修改jmeter.properties中的jsyntaxtextarea.font.family=宋體可以試試看看能不能解決