• jmeter中beanshell postprocessor结合fastjson库提取不确定个数的json参数


    在项目实践中,遇到了这样一个问题。用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的编码环境,确实很不友好。

    总之,通过这次的实践,进一步扩充了自己的知识面,再一次体会到,边走边看,坚持往前走的魅力所在。不要想着准备好所有的必要条件再出发,要用事情来推动自己去创造条件,任何经历都是成长。工作与生活皆如此!

     
     
  • 相关阅读:
    设计模式- 模板方法模式
    什么是Coded UI
    请介绍WCF服务
    我的WCF之旅(1):创建一个简单的WCF程序
    7.3 Models -- Creating And Deleting Records
    7.2 Models -- Defining Models
    7.1 Models -- Introduction
    6.3 Controllers -- Managing Dependencies Between Controllers
    6.2 Controllers -- Representing Multipe Models
    6.1 Controllers -- Introduction
  • 原文地址:https://www.cnblogs.com/jingmu/p/10923254.html
Copyright © 2020-2023  润新知