当前位置 博文首页 > 繁华似锦Fighting:『动善时』JMeter基础 — 31、JMeter中BeanSh

    繁华似锦Fighting:『动善时』JMeter基础 — 31、JMeter中BeanSh

    作者:繁华似锦Fighting 时间:2021-06-02 18:23

    目录
    • 1、BeanShell简介
    • 2、Beanshell的内置变量和方法
    • 3、BeanShell断言界面详解
    • 4、BeanShell断言的使用
      • (1)测试计划内包含的元件
      • (2)登陆接口请求界面内容
      • (3)BeanShell断言界面内容
      • (4)查看运行结果
      • (5)断言结果组件说明
    • 5、补充知识点
      • (1)JSON响应体字段提取及断言
      • (2)响应头解析

    JMeter中的BeanShell断言,可以使用BeanShell脚本来执行断言检查,可以用于更复杂的个性化需求,使用更灵活,功能更强大,但是要能够熟练使用BeanShell语。

    1、BeanShell简介

    Beanshell是一种类似JAVA的脚本语言,通过BeanShell可以对请求数据、响应数据或环境变量进行更加灵活的处理和判断。还可以直接调用外部的JAR包,例如:可以直接引入现成的第三方JSON解析包来使用。

    在JMeter的多种组件中都有BeanShell的身影,如下:

    • 定时器:BeanShell Timer
    • 前置处理器:BeanShell PreProcessor
    • 采样器:BeanShell Sampler
    • 后置处理器:BeanShell PostProcessor
    • 断言:BeanShell Assert
    • 监听器:BeanShell Listener

    在JMeter运行的流程控制中,BeanShell出现的位置,如下图所示:

    image

    2、Beanshell的内置变量和方法

    Beanshell有一些默认的内置变量和方法,用户可以通过这些变量与JMeter进行交互,

    例如:

    • prInt:非GUI模式下打印信息(输出信息到stdout,标准输出控制台)。
    • log:输出信息到日志(文件)
      • log.debu("调试信息")
      • log.info("响应状态码" + ResponseCode)
      • log.warn("警告信息")
      • log.error("出错信息")
    • ResponseCode:响应状态码(String类型)。
    • ResponseHeaders:响应头(String类型)。
    • prev:获取当前请求结果
      • prew.getResponseDataAsString():获取响应体数据(String类型)。
      • prew.getResponseCode():获取状态码(同ResponseCode,String类型)。
    • vars:操作JMeter变量
      • String var1 = vars.get("变量名"):获取变量的值(假设为String类型)。
      • vars.put("变量名", 变量值):设置变量值。
    • props:操作JMeter属性
      • props.get(String,String) 可以获取JMeter中已经生成的属性。
      • props.put(String,String) 可以创建和更新JMeter属性。
    • ctx:获取当前线程上下文数据(可获取所有信息)
      • ctx.getVariables("变量名"):获取变量值(同vars.get())。
      • ctx.setVariables("变量名", "变量值"):设置变量(同vars.put())。
      • ctx.getProperties("属性名"):获取属性值(同props.get())。
      • ctx.setProperties("属性名","属性值"):设置属性(同props.put())。
      • ctx.getPreviousResult():获取当前请求结果同(prev)。
      • ctx.getCurrentSampler():获取当前采样器。
      • ctx.getPreviousSampler():获取前一采样器。
      • ctx.getThreadNum():获取线程数。
      • ctx.getThreadGroup():获取线程组。
      • ctx. getThread():获取当前线程。
      • ctx.getEngine():获取引擎。
      • ctx.isSamplingStarted():判断采样器是否启动。
      • ctx.isRecording():判断是否开启录制。
      • ctx.getSamplerContext():获取采样器山下文数据。

    提示:ctx详细API可参考:JMeter上下文

    3、BeanShell断言界面详解

    添加BeanShell断言组件操作:选中“取样器”右键 —> 添加 —> 断言 —> BeanShell断言

    界面如下图所示:

    image

    BeanShell断言组件的详细说明:

    • 名称BeanShell断言组件的自定义名称,见名知意最好。
    • 注释:即添加一些备注信息,对该BeanShell断言组件的简短说明,以便后期回顾时查看。
    • Reset bsh.Interpreter before each call:每个BeanShell测试元素都有自己的解释器副本(对于每个线程)。如果重复调用测试元素,例如在循环内,除非选择在每次调用之前重置bsh.Interpreter选项,否则解释器将保留在调用之间。一些长时间运行的测试可能会导致解释器使用大量内存。
      由于BeanShell的bsh.Interpreter存在内存泄露,常规方法无法支持长时间的压力测试。JMeter官网推荐,在使用BeanShell进行长时间测试时,打开选项Reset bsh.Interpreterbefore each call,则在每次调用BeanShell程序前,都把解释器重置,以释放解释器之前占用的内存。
    • 参数 (-> String Parameters和String[]bsh.args):输入String参数。String []bsh.args是主类main函数的形式参数,是一个String 对象数组,可以用来获取命令行用户输入进去的参数。
    • 脚本文件:脚本文件(可以填入脚本文件路径),可以点击后边的浏览选择脚本文件。
    • Script (see below for variables that are defined):编写脚本,参照下文定义的变量(使脚本文件参照定义的变量来运行)

    4、BeanShell断言的使用

    BeanShell断言中可以通过ResponseCodeResponseHeaderspre.getResponseDataAsString()来分别获得String格式的响应状态码、响应头、响应体数据。结合if判断,通过变量Failure=falseFailure=true来设置断言是否通过。当设置Failure=true时,还可以设置FailureMessage来设置失败原因。

    我们以一个登陆接口,来演示BeanShell断言组件的应用。

    (1)测试计划内包含的元件

    添加元件操作步骤

    1. 创建测试计划。
    2. 创建线程组:选中“测试计划”右键 —> 添加 —> 线程(用户) —> 线程组
    3. 在线程组里面,添加取样器“HTTP请求”组件:选中“线程组”右键 —> 添加 —> 取样器 —> HTTP请求
    4. 在取样器下,添加断言“BeanShell断言”组件:选中“取样器”右键 —> 添加 —> 断言 —> BeanShell断言
    5. 在取样器下,添加监听器“断言结果”组件:选中“取样器”右键 —> 添加 —> 监听器 —> 断言结果
    6. 在线程组里面,添加监听器“察看结果树”组件:查看结果,选中“线程组”右键 —> 添加 —> 监听器 —> 察看结果树

    最终测试计划中的元件如下:

    image

    点击运行按钮,会提示你先保存该脚本,脚本保存完成后会直接自动运行该脚本。

    (2)登陆接口请求界面内容

    标准的Post请求,填写请求的基本信息和参数即可。

    编写内容如下:

    image

    (3)BeanShell断言界面内容

    我把只要把自己编写的BeanShell代码,复制到Script (see below for variables that are defined)下的输入框即可。

    如果需要进行模拟压力测试的时候,可以勾选上Reset bsh.Interpreter before each call选项。我们这里不用。

    编辑好的界面,如下图所示:

    image

    说明

    1)状态码断言代码

    //状态码断言
    log.info("状态码:" + ResponseCode);
    if(ResponseCode.equals("200")){ 
    	Failure=false;	// 表示断言成功
    }
    else{
    	Failure=true;	// 表示断言失败
    	FailureMessage="响应状态码非200";  // 自定义的失败信息
    }
    

    注:字符串只能使用双引号,字符串相等要使用" ".equals(" ")表达式。

    2)响应体包含特定内容断言代码

    //获取响应数据
    String response = prev.getResponseDataAsString();
    log.info("响应体:" + response);
    //响应数据包含
    if(response.contains("登录成功")){
    	Failure=false;	// 表示断言成功
    }
    else{
    	Failure=true;	// 表示断言失败
    	FailureMessage="响应数据不包含登录成功";
    }
    

    (4)查看运行结果

    我们在察看结果树组件中,观察脚本运行之后的结果。

    如果断言正确,和正常发送请求一样,如下图:

    image

    如果断言失败,则会出现断言失败的提示,如下图所示:

    image

    (5)断言结果组件说明

    也添加断言结果监听器,通过断言结果组件来判断断言是否通过。

    如下图所示:

    image

    说明:

    • 已通过的断言仅显示取样器名称。
    • 未通过的,除了显示取样器的名称,还显示错误原因。

    5、补充知识点

    (1)JSON响应体字段提取及断言

    将String类型的响应体转为JSON对象并操作需要额外的JAR包,可以使用org.json.jargson.jar

    json.jar为例,下载后将其放入JMeter/lib目录下,重启JMeter,添加BeanShell断言代码,如下:

    //JSON响应断言
    import org.json.*;   //导入org.json包
    
    String response = prev.getResponseDataAsString();  //获取响应数据
    JSONObject responseJson = new JSONObject(response);  //转为JSON对象
    
    String message = responseJson.getString("message"); 
    log.info("响应message字段:" + message);
    
    if(message.equals("成功")){
    	Failure=false;
    }
    else{
    	Failure=true;
    	FailureMessage="响应message字段非成功";
    }
    

    JSONObject对象除了getString()方法外,还支持:

    • getBoolean("字段名") :获取布尔类型字段值。
    • getInt("字段名"):获取整型字段值。
    • getLong("字段名"):获取长整型字段值。
    • getDouble("字段名"):获取双精型字段值。
    • getJSONObject("字段名"):获取嵌套Object类型字段值,JSONObject类型。
    • getJSONArray("字段名"):获取嵌套Array类型,JSONArray类型。

    (2)响应头解析

    响应头原本为String类型,可以通过分割遍历组装成Map类型来提取响应头中的项

    Copyimport java.util.HashMap;
    import java.util.Map;
    
    //将字符串用换行符 截取为adc数组
    String [] headersList = ResponseHeaders.split("\n");
    
    Map headersMap = new HashMap();   //创建HashMap来从新组装headers
    
    for(int i=1;i<headersList.length;i++){
    	String [] itemList=headersList[i].split(": ");   // 将每一条Headerr项按冒号分割
    	headersMap.put((itemList[0]), itemList[1]);   // 分键值放入HashMap
    }
    
    String contentType = headersMap.get("Content-Type");   // 提取相应项
    log.info("响应Content-Type:" + contentType)
    

    参考:https://www.cnblogs.com/superhin/p/12359794.html

    bk