1.简介
jmeter 因其开源免费的特性,目前已经全面应用于性能测试、自动化测试领域,本讲将通过讲解一些高阶特性,帮助大家更好的使用 jmeter。本次讲堂主要讲解的内容如下:
- jmeter 中逻辑控制器的使用
- jmeter 生成多维度的 HTML 测试报告
- jmeter 中 Bean shell 的正确使用姿势以及注意事项;
- jmeter 如何实现接口间的参数传递
- jmeter 如何自定义一个函数
- jmeter 随机控制业务比例
- jmeter 测试 dubbo 接口的配置实现
- jmeter 如何实现 ip 欺诈
下面我将一一对其进行讲解;
2.重点内容
2.1 jmeter 中逻辑控制器的使用
jmeter 的八大组件之一即是逻辑控制器,它主要用来控制 Sampler(采样器)的执行顺序,因此我们使用逻辑控制器的时候,必须和采样器一起使用;jmeter 提供了如下 18 种逻辑控制器;
以上 18 种逻辑控制器中,最常用的有:Switch Controller、循环控制器、仅一次控制器、随机控制器、简单控制器 5 种,其他 13 种逻辑控制器可依据自己需要自行学习了解;
2.1.1Switch Controller
通过给 Switch Value 进行赋值进而指定执行的 Sampler(采样器),Switch Value 的值从 0 开始;
如上图,我们此时将 Switch Value 值设置为 1 ,运行结果如下:
2.2.2循环控制器
循环控制器主要用来控制其作用域下采样器的循环运行次数;
如上我们设置循环执行次数为 10 ,此时查看下运行结果:
2.2.3仅一次控制器
在一个测试计划下,此控制器下的采样器只会被执行一次,这个控制器通常会用于"用户登陆"、"系统退出"、连接数据库 等一次性操作的场景;
如上我们将仅一次控制器作用于 HTTP02,循环控制器作用于 HTTP01、仅一次控制器,此时查看运行结果:
2.2.4随机控制器
随机选择其作用下的采样器进行执行,注意即使其下面有多个采样器,每次只会随机选择一个进行执行,经常应用于冒烟测试以及页面的随机访问;
2.2.5简单控制器
它的存在并不是为了任何的逻辑控制以及运行时功能,它存在的目的是为了方便我们对多个采样器进行分组管理,达到模块化效果,通俗的讲,就是为了美化工程结构;
2.2jmeter 生成多维度的 HTML 测试报告
jmeter 自带一些测试报告模板,但是这些模板样式简陋,故而在 jmeter 3.2 版本以后可以使用仪表盘报告(Dashboard Report),生成多维度的 HTML 可视化报告;
2.2.1准备
- 必须使用 jmeter 3.2 以后的版本才可以使用 Dashboard Report 的功能
- 必须配置 jmeter 环境变量,配置方式如下:
第一步:新建系统变量 JMETER_HOME
第二步:在 PATH 环境变量中增加 JMETER_HOME 的 bin 目录;
2.2.2应用
如果在 Windows 系统下,我们需要打开命令行窗口,cd 到 .jmx 脚本所在的目录下,执行如下命令即可:
jmeter -n -t <.jmx脚本> -l result.jtl -e -o <HTML 报告生成路径>
出现下图即为生成成功
对上述命令中的参数进行说明如下:
- -n :以非 GUI 形式运行 Jmeter;
- -t :.jmx 脚本所在的路径;
- -l :result.jtl 运行结果保存文件路径(.jtl),此文件必须不存在,如果存在,则执行:
jmeter -g result.jtl -o /Jmeter/apache-jmeter-3.3/htmlReports
命令;
- -g : result.jtl 已经存在的 .jtl 文件的路径;
- -e :在脚本运行结束后生成其对应的 html 报告;
- -o :存放 html 报告的路径;
此时在指定的路径下即可查看测试报告,报告整体样式如下:
2.2.3HTML图表信息详解
报告整体分为两部分: Dashboard(仪表盘)和 Charts(图表)
2.2.3.1 Dashboard(仪表盘)
2.2.3.2Charts(图表)
图表中的样例偏多,着重介绍一些需要重点关注的图表信息:
- 根据响应时间、TPS、以及并发数来判断性能测试拐点;
- 脚本运行期间成功的请求与响应时间的占比分布图,与 jmeter 自身的聚合报告一致;
- 脚本运行过程中的吞吐量变化趋势图,用来判断吞吐量的变化
- 衡量性能测试的重要指标, TPS(每秒事务数)图表
2.3jmeter 中 Bean shell 的正确使用姿势以及注意事项
2.3.1 什么是 Bean shell
Bean shell 是一种满足 java 语言规范的松散型语言,请注意松散二字,即不需要严格按照 java 语言的书写规范去做,但是大多数情况下,我们只需要按照和 java 同样的语法规范去做即可,当然特例除外:
- 打印输出: Bean shell 中的打印输出函数为 log.info;
- 对于集合的使用:在 Bean shell 中使用 java 的集合框架,例如 List 集合,在 java 中我们需要声明泛型然后通过子类进行实例化,而在 Bean shell 中无需指定泛型,直接实例化即可,例如: List list = new ArrayList();
- 在 Bean shell 中无需编写类
2.3.2 jmeter 中哪些地方可以使用 Bean shell
Bean shell 在 jmeter 中可以说无处不在,主要在如下组件中有所应用:
-
定时器: BeanShell Timer
-
前置处理器:BeanShell PreProcessor
-
采样器: BeanShell Sampler
-
后置处理器:BeanShell PostProcessor
-
断言: BeanShell断言
-
监听器: BeanShell Listener
2.3.3 Bean shell 的使用举例
下面我们通过前置处理器:BeanShell PreProcessor 进行演示,Bean shell 在其他组件中的应用可以触类旁通;
Bean shell 可以通过两种方式使用 java 代码,第一种是引用外界 jar 包,第二种直接在 Bean shell 编辑界面进行引用;
2.3.3.1引用 jar
使用步骤如下:
- 第一步:通过 ILDE 将需要使用的 java 类导出为 jar,如果这个类本身有依赖,也需要将其依赖的类导出为 jar;
- 第二步:直接引用的 jar 放到 \apache-jmeter-3.3\lib\ext 目录下,其依赖的 jar 导入到 \apache-jmeter-3.3\lib 目录下;
- 第三步:打开 jmeter,在测试计划下新增线程组,在新增线程组下添加一个 http 采样器,在 新增的 http 采样器下新增前置处理器 Bean PreProcessor
- 第四步:在测试计划下引入依赖的 jar 包,点击保存;
- 第五步:在前置处理器 BeanShell PreProcessor 中引入 jar 包;
import org.hai.*; import java.util.Calendar; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; //引入自动生成身份证号的类 IdCardGenerator g = new IdCardGenerator(); //生成身份证号 String loanCertiCode = g.generate(); if (Integer.parseInt(loanCertiCode.substring(16).substring(0, 1)) % 2 == 0){ String sex = "F"; vars.put("gender",sex); }else { String sex = "M"; vars.put("gender",sex); } //将身份证号赋值给loanCertiCode变量,依靠${loanCertiCode}引用它即可 vars.put("loanCertiCode",loanCertiCode);
- 第六步:在 http 采样器中使用前置处理器中提供的身份证号、性别作为变量进行引用;
- 第七步:查看结果树,观察下测试结果:
2.3.3.2 直接编辑 Bean Shell
我们既能直接引用 jar,自然也可以直接编写 java 代码,示例如下:
- 我们将如下实现格式化时间的代码直接放置到前置处理器中:
package com.times; import java.text.SimpleDateFormat; import java.util.Date; /** * 类注释 * * @author Lenovo * @Title: Time01 * @ProjectName mystudyproject * @Description: TODO * @date 2019/12/3111:31 */ public class Time01 { public static void main(String[] args) { Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd" ); String formatDate = sdf.format( date ); System.out.println( "格式化的日期:" + formatDate ); } }
放置到 Bean shell 格式化后的代码如下:
import java.text.SimpleDateFormat; import java.util.Date; Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd" ); String formatDate = sdf.format( date ); vars.put("date",formatDate);
- 第二步:在 http 采样器中引入日期变量
- 第三步:查看结果树,观察下测试结果:
2.3.4Bean shell 常用的内置变量
Meter在它的BeanShell中内置了变量,用户可以通过这些变量与JMeter进行交互,其中主要的变量及其使用方法如下:
-
log:写入信息到jmeber.log文件,使用方法:log.info(“This is log info!”);
-
vars - (JMeterVariables):操作jmeter变量,它是测试用例与BeanShell交互的桥梁,常用方法:
a) vars.get(String key):从 jmeter 中获得变量值
b) vars.put(String key,String value):将数据保存到 jmeter 变量中
-
props - (JMeterProperties - class java.util.Properties):操作jmeter属性,该变量引用了JMeter的配置信息,可以获取Jmeter的属性,它的使用方法与vars类似,但是只能put进去String类型的值,而不能是一个对象。对应于java.util.Properties。
a) props.get("START.HMS"); 注:START.HMS为属性名,在文件jmeter.properties中定义
b) props.put("PROP1","1234");
-
prev - (SampleResult):获取前面的sample返回的信息,常用方法:
a) getResponseDataAsString():获取响应信息
b) getResponseCode() :获取响应code;
2.3.5调试技巧
最后给大家一个技巧。就是无论是编写还是调试 Bean shell 的脚本,最好都是在开发工具中进行,一定不要在 jmeter 的Bean shell 中直接编写;
另外直接引入 jar 包的形式应该是我们所推崇的方式;
2.4jmeter 如何实现接口间的参数传递
这小节主要讲解接口间的参数传递,即从上一个接口中获取响应信息后,作为下一个接口的请求参数。
2.5jmeter 如何自定义一个函数
jmeter 的函数助手已经封装了许多常用的函数,但是有些时候,也可能不能完全满足我们的测试需要,因而我们可以根据自己的测试需要编写属于我们自己的函数。
2.5.1前提条件
- 本地自行配置 java 开发环境,选择好开发工具,idea 或者 Eclipse 都可以;
- 在 idea 中新建一个 maven 工程,在新建的工程里新建一个包,注意包名必须以 functions 进行结尾;
- 在 pom.xml 文件中导入 jmeter 的依赖,主要为ApacheJMeter_core、ApacheJMeter_java、ApacheJMeter_functions 依赖文件如下:
<dependency> <groupId>org.apache.jmeter</groupId> <artifactId>ApacheJMeter_core</artifactId> <version>3.3</version> </dependency> <dependency> <groupId>org.apache.jmeter</groupId> <artifactId>ApacheJMeter_java</artifactId> <version>3.3</version> </dependency> <dependency> <groupId>org.apache.jmeter</groupId> <artifactId>ApacheJMeter_functions</artifactId> <version>3.3</version> </dependency>
2.5.2函数实现 API
要想实现自定义函数,必须要继承类 AbstractFunction 且覆写其全部方法,AbstractFunction 包含以下四个方法;
方法名称 | 方法描述 | 参数含义 |
@Override public String execute(SampleResult sampleResult, Sampler sampler) throws InvalidVariableException { return null; }
|
将上一个采样器的执行结果以及当前采样器作为参数传递给此方法后,返回当前函数的执行结果 |
SampleResult sampleResult:上一个采样器执行的结果 Sampler sampler:当前采样器 |
@Override public void setParameters(Collection<CompoundVariable> collection) throws InvalidVariableException { }
|
用于传递用户在执行过程当中传入的实际参数值,从该方法传入的参数值会保存在类全局变量里,可以被后续的 execute() 方法调用,且此方法无论当前函数是否有参数,都会被调用,
另外,我们也可以增加对传入参数的检查机制,防止出现错误。
checkMinParameterCount 检查最少需要输入的参数数量,达不到就自动报错。checkParameterCount 检查输入的参数个数是否符合给定的数量或者范围,不符合报错。this.values = collection.toArray(); 将输入的参数值传递到value 。 |
|
@Override public String getReferenceKey() { return null; }
|
返回当前函数的名字。JMeter的命名规则是在函数名前面加入双下划线
__ 。比如__IntSum ,函数的名字与类名一致,而且该名字应该以static final 的方式在实现类中定义好,防止在运行过程中被篡改。 |
|
@Override public List<String> getArgumentDesc() { return null; }
|
方便 jmeter 识别当前实现函数的描述 |
2.5.3具体编码实现