在JMeter的应用中,可利用BeanShell类元件承载用户自定义的处理逻辑,经常用于执行额外的数据加工、转换、识别、记录等操作。BeanShell到底是什么?在JMeter的应用中如何更好的利用好BeanShell类元件?本文将详细进行介绍。
一、BeanShell介绍
BeanShell是一种Java编写的小型、免费、可嵌入的Java源代码解释器,通常采用jar包引入的方式使用。BeanShell即具有脚本语言特性,又可识别执行标准Java语法,并且支持扩展类的脚本语法。所以BeanShell脚本可以看成一段支持脚本语法功能的Java代码。所以首先明确BeanShell是独立开发维护的开源项目,并非JMeter特有或设计。
BeanShell支持的语言特点使它可动态运行Java代码片段,还可以调用虚拟机内的其他Java应用代码,自由的引用类、方法和程序设计功能。透明化和可自主定义的调用执行,加上自身具备精简的脚本类语法特性,让BeanShell在动态调用Java功能的工具嵌入场景中成为了十分优秀的选择。
二、JMeter中的BeanShell 组件
了解BeanShell介绍后,再来看JMeter中相关配置元件,不难发现BeanShell相关组件就是在 JMeter执行链路不同环节中发挥动态调用功能的。用户可以利用BeanShell组件自定义编写或引入特定处理逻辑,在JMeter脚本运行环节中实现对信息和数据的动态处理效果。目前JMeter中支持BeanShell的元件有如下类别。
JMeter中的BeanShell元件
1、BeanShell Sampler采样器
BeanShell Sampler提供给用户自定义测试处理逻辑的功能,在实际的测试中测试场景往往伴随具体的交互协议,单纯使用BeanShell 采样器做测试交互的场景较少。但由于采样器可提供独立运行的处理环节,因此可用来执行或测试数据加工逻辑。
采样器元件界面比较简单,上方配置区域可设置入参数据、执行选项,用户需在下方脚本框自定义编写逻辑代码或引入已写好的脚本文件。
在入参数据设置时需要注意,当前JMeter仅支持String字符串类型的参数传递。传参可传入参数元件配置好的参数数据,用${参数名}来引用,也可以直接传入参数的值。所有参数需要用空格分开,参数数据会被保存在bsh.args数组中,在脚本中引用参数需要用bsh.args和下标寻找到对应参数。
下方说明了元件支持的功能变量。SampleResult保存了当前请求和响应的信息;ResponseCode记录了Sampler交互结果的状态码,默认为200;ResponseMessage保存了交互的响应信息,默认为"OK";IsSuccess为判断请求是否成功的状态变量,默认为true;Label为采样器设置的名称标签,就是图中的Name区域;FileName保存了Script file区域设置的外部BeanShell脚本文件名。还有ctx\vars\props等公共变量,将在下文中详细介绍。
2、BeanShell PreProcessor前置处理
BeanShell前置/预处理元件为用户提供了在测试交互前的数据处理功能,可以在输入Sampler之前进行数据转换或不同逻辑下的数据替换,比如在http交互前部分数据需要做额外的加密处理,此时可以在前置元件中设计加密逻辑代码,完成测试的数据加密要求。元件界面如下所示,和Sampler基本一致。
在元件提供的调用变量中和Sampler元件有所不同,Sampler变量提供了对当前元件所属Sampler的对象引用。
3、BeanShell PostProcessor后置处理
BeanShell后置处理元件和预处理元件在测试步骤上相对,预处理元件是在Sampler交互之前调用执行,而后置处理元件提供了Sampler交互完毕后,对交互结果进行额外的处理的功能。通常用于处理响应数据,包括解密、转换、提取等操作。
后置处理元件中prev对象可引用本次Sampler交互的响应结果SampleResult对象,搭配自定义的处理逻辑,实现获取、修改响应结果的功能。data则存放了当前请求的响应数据,为byte[]类型。
4、BeanShell Timer定时器
BeanShell Timer定时器可以让采样器根据用户自定义逻辑触发不同的等待功能。通常直接使用Thread.sleep()方法完成对当前线程的延时处理。
5、BeanShell Assertion断言
BeanShell断言可以实现用户自定义逻辑的交互状态判断,本质提取数据并进行转换对比。在本元件将内置对象分为了两类,一类是可读可写,包括SampleResult、Failure、FailureMessage等,可以对其中数据进行修改,实际亦可通过SampleResult的setResponseData方法修改相应数据,这也是后置处理元件的功能,但通常为确保元件的功能独立性不进行这样操作。另一类内置对象仅提供只读功能,包括Response的数据和Sampler中的数据等。
三、JMeter中BeanShell通用操作
尽管不同种类BeanShell元件在JMeter执行链路中提供了多种功能,但在与JMeter耦合的通用交互上,BeanShell元件还是有一些通用操作。上文在介绍不同类别元件时,界面下方罗列出了元件支持的不同对象变量,可以看到一些相同的内置对象。这和虚拟机共享有分不开关系,毕竟透明化的动态调用,让BeanShell具备了访问JMeter公开的方法和数据。下面将分别介绍JMeter中BeanShell的内置通用对象功能。
ctx保存了当前线程的上下文信息,属于JMeterContext的对象引用,可以获取到当前线程的信息、Sampler、变量、属性值等。包括可用getCurrentSampler()方法获取当前sampler请求;用ctx.getThread()获取当前执行线程;用ctx.getVariables()获取当前的线程变量等。
vars提供了操作JMeter线程变量的功能,实际引用的是保存JMeter线程变量的JMeterVariables对象,其中数据以key-value形式保存在Map结构中,因此存取都是用get和put方法,支持String类型或Object类型的访问操作。用vars.get(String key)或vars.getObject(String key)获取数据,用vars.put(String key, String value)和vars.put(String key, Object object)创建变量。这里操作的变量数据都是和当前线程绑定的,可以理解为threadlocal中,因此变量的变化不涉及对其余线程的影响。
log提供记录日志的功能,可硬log.info()或log.error()将自定义信息输入bin目录下的jmeter.log文件中,这也是JMeter的主日志记录文件。
props引用的是JMeter的配置信息,可存取 JMeter全局静态变量,也就是jmeter.properties文件中的属性值,同样是key-value的保存形式。
prev引用的是SampleResult对象,和ctx.getPreviousResult()相同获取上一个Sampler返回的信息,本对象在Beanshell后置处理器和定时器都有出现。可用getResponseDataAsString()获取响应信息。需要注意的是如果prev所在元件执行步骤在Sampler之前,perv就是上一次Sampler的请求结果。
四、JMeter中BeanShell引入外部功能
在JMeter的使用中,除了可以在BeanShell元件中自行编写java代码或使用脚本化语法外,BeanShell元件同样支持引入外部已定义好的Java功能,可在元件中进行外部引入设置。引入方式有如下三种。
引用外部java源文件。可用JMeter内置的source函数来引用Java源文件。source("代码路径")引入需要写绝对路径。
引用外部已编译好的字节码文件。JMeter提供addClassPath函数引用字节码文件。找到已编译好的字节码.class文件,用addClassPath("字节码文件路径")后,需要import导入包及类即可使用。
引入java或字节码文件示例
引用外部jar包。若需要引入较多的外部功能,则可以通过打包引入的方式。可以将jar包放入到JMeter根目录的/lib/ext目录下,重启JMeter后即可生效使用;或者在Test Plan界面下Add directory or jar to classpath手动添加jar包。
放置到ext目录下,重启生效
在Test Plan界面下手动引入(即时生效)
五、JMeter中BeanShell实战演示
接下来将实战演示不同beanshell组件的全流程应用过程,主要内容为根据变量的值触发不同组件中逻辑的变化,对数据进行修改、增加等操作,随即改变本次交互的执行结果和信息。
自定义参数。自定义了两个变量para1初始值为”hello”,para2初始值为”world”。还引入了自增数据元件和随机数据元件,分别定义为counter和random,四个变量用于演示执行逻辑中的数据变化。
自定义变量
前置处理元件设计。需要注意交互启动前,首先执行的是前置元件。在入参中传入para1参数,代码中通过bsh.args的数组方式和vars.get分别演示了不同引用变量方法。当首个传参变量为hello时,将写逻辑为如果传入的首个参数为”h”,则新建变量para3为”hello”。
前置处理元件设计
定时器元件设计。设置定时器触发逻辑,当上下文变量表中包含para3,并且值为”good”时,延时一秒后再启动交互。也就是承接前置处理元件的结果触发不同逻辑。
定时器逻辑
采样器元件设计。首先设置引入外部代码文件。使用source引入外部.java文件。其中的代码如下图所示,主要实现的是传入参数的字符串合并逻辑。在实际的使用中其中可以是比较复杂的数据处理逻辑,像加密解密、偏移提取等。
文件引入
代码逻辑
引入外部Java文件后开始编写插件内逻辑编码,在本次实践中传入了para1、para2和random三个已定义好的参数作为入参。通过判断random是否可以被3整除进入不同逻辑,同时设置响应码、响应信息、响应数据。如果可以被3整除,则新建变量para4,执行外部Java文件的concat方法,拼接为para1+para2,同时设置响应码为888,响应信息修改为“逻辑触发”和随机变量的拼接,响应数据则修改为新建的para4和counter自增器变量值的拼接字符串。
采样器逻辑
后置处理元件设计。采样器元件执行完毕后进入后置处理元件,本元件中的代码逻辑为判断上次交互是否在采样器逻辑中创建了para4变量,进行响应数据的修改,在原始结果中拼接“进入逻辑”或“没有进入逻辑”字符串。
后置元件逻辑
断言元件设计。加入断言元件对测试结果进行额外判断和处理。元件中写入了两个处理逻辑,当自增变量counter为001或响应数据中包含“hello”时,均将测试结果修改为成功。在断言元件中的可有效提取响应结果数据片段并根据业务逻辑修改交互结果。
断言逻辑
整个响应交互完成,可以在结果树中查看本次请求的最终结果。上述逻辑的激活顺序和变量输出信息如下日志面板所示。
日志输出展示
六、使用总结
对BeanShell的理解要明确其具有的脚本化和Java标准语法的支持特性,嵌入在Java应用中共享虚拟机的机制让BeanShell具有很高的访问透明度,为最大化发挥脚本逻辑提供关键保证。
在JMeter中使用BeanShell元件,可以很方便的让用户自定义测试处理、执行逻辑,尤其是在复杂场景下,工具自带的元件组合面临无法满足业务复杂逻辑的要求,可以考虑使用BeanShell自定义执行链路,像常见的数据加密解密、根据数据属性执行不同分支、自定义执行结果等功能,都可以在Beanshell元件中很好实现。因此掌握BeanShell的使用,对基于JMeter开展的测试工作具有很好的辅助效果。
作者:杨易寰
来源:51Testing软件测试网原创