前言
众所周知JMeter是业内公认的性能测试工具,功能十分强大且易于拓展,但是入门有一定门槛,需要明白一些基本概念。本文使用了HTTP取样器、TCP取样器、响应断言、JSON提取器等组件,对公司现存的登录流程进行了测试。公司的产品包含了HTTP和TCP接口,对于HTTP可以直接使用JMeter进行测试,但是TCP由于使用了特殊协议,所以需要重写拓展实现自定义协议。
基本概念
- 测试计划:顶级文件夹,概念类似于java项目
- 线程组:运行线程的容器,类似于java线程池,可以设置线程数、失败策略、循环次数等参数
- 取样器:从外部接口获取数据的组件,支持很多访问协议,可以理解为一个接口访问者
- 响应断言:对接口返回内容进行匹配,从而标记接口是否响应成功
- 提取器:从接口返回值中提取关键数据到JMeter上下文中,可以在其它地方使用${key}获取
- 查看结果树:显示接口请求和返回数据
- 聚合报告:生成测试的报告,包含请求次数、响应时间、失败数量等性能指标
- 响应时间图:以图表的形式显示响应时间,需要自行设置横纵坐标参数,且不能实时刷新
- 临界部分控制器:确保线程组中所有接口按序执行
安装
直接在JMeter官网下载压缩包后解压即可,下载地址apache-jmeter-5.5。注意解压路径不要有中文,解压后打开apache-jmeter-5.5\bin\ApacheJMeter.jar即可运行。请确保本机环境有jdk1.8及以上版本。
基本使用
1.创建线程组
步骤:右击测试计划-》添加-》线程-》线程组
线程数:同时有多少个线程运行,即同时并发多少用户
Ramp-up时间:线程在多少秒内启动完毕,如线程数太多时可以设置时间长一点
循环次数:每个线程循环多少次
2.创建取样器
步骤:右击线程组-》添加-》取样器-》HTTP请求
协议:http或者https
服务器或ip:127.0.0.1
端口:80
路径:/user/login
参数:请求提交的参数,先点击添加后双击列表项,列表值可以使用${key}获取上下文中的变量
其余参数按需填写
3.JSON提取器
步骤:右击HTTP请求-》添加-》后置处理器-》JSON提取器
names of created..:取出变量在JMeter上下文中的名字,也就是后续使用${key}获取时的key
JSON Path..:返回值的提取路径,如:$.data.userId,对应返回json:{data:{userId:123}}
4.其它
篇幅有限,其余组件不一一列举,使用方法大同小异,如有不懂可以执行搜索。后文会提供完整的项目文件供参考。
自定义TCP取样器
使用TCP取样器时默认提供的TCPClient太局限,无法满足自定义TCP协议的场景,这里重写官方的TCPClient实现自定义协议,完成TCP测试工作。
1.创建maven项目
安装idea指引创建默认的maven项目即可,注意配置的groupId和artifactId,这个需要用于在后续JMeter中指定TCPClient。
2.maven依赖
<dependencies>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_core</artifactId>
<version>5.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_tcp</artifactId>
<version>5.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
3.maven编译
<build>
<finalName>test-jmeter-tcp</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
4.代码编写
JMeter在请求前会调用write方法,其中是String s就是TCP取样器中要发送的文本,在响应后会调用read方法,返回输入流供自定义读取。
这里在发送请求时先写入请求序号,然后写入请求体的长度,最后再写入请求体。本处的自定义协议规定长度为4字节采用大端在前的方式。
这里在收到返回值时跳过了前面自定义的24位数据,这些数据在自定义协议里标识了请求信息,这里不做校验,直接读取24位数据之后的响应体并以UTF-8解析。需要注意的是一般来说TCP都是长连接,服务器在请求后不会主动断开链路,这里JMeter无法知道服务器数据响应完成,本处的自定义协议也无法使用固定的EOL字符标记,所以采用了一个较大是数组读取,确保一次性能够读完响应值后直接返回,不然JMeter会一直等待响应知道超时。
package com.test.jmeter;
//引用省略
public class TTcpClientImpl extends AbstractTCPClient {
//请求序号
private int req = 1;
@Override
public void write(OutputStream outputStream, InputStream inputStream) {
throw new UnsupportedOperationException(
"Method not supported for Length-Prefixed data.");
}
@Override
public void write(OutputStream outputStream, String s) throws IOException {
byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
//req
outputStream.write(req);
req++;
req = req > 0xff ? 1 : req;
//length
int length = bytes.length;
outputStream.write((byte)(length >> 24));
outputStream.write((byte)(length >> 16));
outputStream.write((byte)(length >> 8));
outputStream.write((byte)length);
outputStream.write(bytes);
outputStream.flush();
}
/**
* @param inputStream
* @deprecated
*/
@Override
public String read(InputStream inputStream) throws ReadException {
//使用一个足够大的缓冲,避免TCP连接一直无响应到超时
//协议无法使用固定的结尾进行分割(EOL),所以这里用大缓存一次读完
byte[] bytes = new byte[4096];
StringBuilder sb = new StringBuilder(4096);
SampleResult sampleResult = new SampleResult();
try {
//自定义读取开始
inputStream.skip(24);
inputStream.read(bytes);
//自定义读取结束
sampleResult.latencyEnd();
sb.append(new String(bytes, StandardCharsets.UTF_8));
} catch (SocketTimeoutException e) {
if (useEolByte) {
throw new ReadException("Socket timed out while looking for EOM", e,
sb.toString());
}
} catch (IOException e) {
throw new ReadException("Problems while trying to read", e, sb.toString());
}
return sb.toString();
}
}
5.编译使用
直接使用maven的package进行打包,会生成一个名为test-jmeter-tcp.jar的文件,将这个文件放到apache-jmeter-5.5\lib\ext目录,然后重启JMeter。
在TCP取样器中的TCPClient classname中填入我们的class路径即可使用自定义的client,这里我们填入com.test.jmeter.TTcpClientImpl。
最终效果