JMeter Java请求开发方法
Jmeter支持多种请求方式,这里要介绍的是通过编写java实现的Java请求方式。
http请求适合大部分场景,用户能够自定义报文头、报文体、Content-Type等信息。但对于自定义拆组包,或报文带有加解密功能的情况,此时使用http请求可能就不那么容易了(可能通过beanshell也能实现,没有研究)。对于java开发工程师来说,用java的方式来编写自然是首选方案了,下面介绍如何用java来开发jmeter的java请求。
Java请求快速开始
新建maven工程
<groupId>org.example</groupId>
<artifactId>hello-jmeter</artifactId>
<version>1.0-SNAPSHOT</version>
hello world
没在官网找到java请求的开发教程,直接百度了:
Jmeter 使用-JAVA请求 - 冰蓝小猪宝宝 - 博客园
参考这个,写个hello world:
添加依赖
1.在工程根目录下,创建lib目录,将apache-jmeter-5.6.3/lib/ext目录下的ApacheJMeter_core.jar文件和ApacheJMeter_java.jar文件复制到lib目录
2.在maven中添加system依赖:
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_core</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/ApacheJMeter_core.jar</systemPath>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_java</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/ApacheJMeter_java.jar</systemPath>
</dependency>
这里的groupId和artifactId是自定义的,因为他是从本地路径读的。
编写Java测试类
编写HelloJavaSample测试类
public class HelloJavaSample extends AbstractJavaSamplerClient {
private AtomicInteger counter = new AtomicInteger(0);
@Override
public void setupTest(JavaSamplerContext context) {
super.setupTest(context);
}
@Override
public void teardownTest(JavaSamplerContext context) {
super.teardownTest(context);
}
public SampleResult runTest(JavaSamplerContext javaSamplerContext) {
System.out.println("hello world!"+counter.incrementAndGet());
SampleResult sampleResult = new SampleResult();
sampleResult.sampleStart();
try {
Thread.sleep(1);
sampleResult.setSuccessful(true);
} catch (InterruptedException e) {
e.printStackTrace();
sampleResult.setSuccessful(false);
}
sampleResult.sampleEnd();
sampleResult.setResponseCode("200");
sampleResult.setResponseMessage("success!");
sampleResult.setSamplerData("hello");
sampleResult.setResponseData("hello world!".getBytes());
return sampleResult;
}
}
打包maven工程
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<outputDirectory>${project.basedir}/result</outputDirectory>
</configuration>
</plugin>
修改jmeter.properties文件
修改bin/jmeter.properties文件,搜索search_paths关键字:
# List of directories (separated by ;) to search for additional JMeter plugin classes,
# for example new GUI elements and samplers.
# Any jar file in such a directory will be automatically included,
# jar files in sub directories are ignored.
# The given value is in addition to any jars found in the lib/ext directory.
# Do not use this for utility or plugin dependency jars.
#search_paths=/app1/lib;/app2/lib
search_paths=F:/my-practice/backend/hello-jmeter/result
这里的路径按自己的真实路径填写。
启动jmeter
点击右侧下拉选择,可以看到我们刚添加的HelloJavaSample类,选中。
添加必要的监听器 单笔测试
可以看到运行了1次测试,tps是1000,也能看到请求响应报文。
另外,观察控制台输出,可以看到每次都是1.也就是说每次jmeter都相当于new了一个你的java类,来进行测试的,准确的说是每个线程在整个运行过程中,使用同一个sample对象。
正式开发
以添加fastjson和hutools为例,来演示如何添加依赖包,以及添加依赖包后如何打包。
1.添加依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.4</version>
</dependency>
2.开发代码
public class HelloJsonSample extends AbstractJavaSamplerClient {
private AtomicInteger counter = new AtomicInteger(0);
private JSONObject template = new JSONObject();
private String url = "http://localhost:8081/post";
@Override
public void setupTest(JavaSamplerContext context) {
template.put("name", "HelloJsonSample");
template.put("version", "1.0.0");
}
@Override
public void teardownTest(JavaSamplerContext context) {
super.teardownTest(context);
}
public SampleResult runTest(JavaSamplerContext javaSamplerContext) {
int count = counter.incrementAndGet();
template.put("count", count);
SampleResult sampleResult = new SampleResult();
HttpResponse httpResponse = null;
String body = template.toJSONString();
sampleResult.setSamplerData(body);
try {
sampleResult.sampleStart();
httpResponse = HttpRequest.post(url).body(body).timeout(60000).execute();
sampleResult.sampleEnd();
} catch (Exception e) {
e.printStackTrace();
sampleResult.sampleEnd();
sampleResult.setSuccessful(false);
sampleResult.setResponseMessage(e.getMessage());
return sampleResult;
}
String resBody = httpResponse.body();
// 解析返回报文
JSONObject resJson = JSON.parseObject(resBody);
String code = resJson.getString("code");
String retMsg = resJson.getString("retMsg");
sampleResult.setResponseCode(code);
sampleResult.setResponseMessage(retMsg);
sampleResult.setResponseData(httpResponse.bodyBytes());
sampleResult.setSentBytes(httpResponse.bodyBytes().length);
if(!Objects.equals("000000", code)) {
sampleResult.setSuccessful(false);
} else {
sampleResult.setSuccessful(true);
}
return sampleResult;
}
}
这里有几点需要说明一下:
a.sampleResult.sampleStart()和sampleResult.sampleEnd()方法,不是在最外面的,而是在http调用的地方,这样统计出的响应时间更准确。
b.成功失败根据返回报文解析后的结果判断,这也符合业务需要
c.这里构造了一个template对象,这样每次迭代可以复用这个对象,公共请求信息不用每次添加。
3.复制依赖配置
将依赖也打包到${project.basedir}/result目录,同时排除掉jmeter的依赖(因为jmeter默认加载)。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.basedir}/result</outputDirectory>
<excludeGroupIds>org.apache.jmeter</excludeGroupIds>
</configuration>
</execution>
</executions>
</plugin>
这段配置是为了自动复制工程依赖到result目录下,同时忽略掉jmeter那两个systemPath的依赖。
4.准备模拟服务端
用springboot启动一个简易的http服务端。
@PostMapping("/post")
public JSONObject post(@RequestBody Map<String, String> map){
JSONObject json = new JSONObject();
json.put("code", "000000");
json.put("retMsg", "success");
json.put("origin", map);
log.info("接收到报文:{}", map);
return json;
}
修改对应的url地址。
5.打包并测试
打包前先停掉jmeter。打包结果为:
重新启动jmeter,添加新的线程组、添加java Request。
结果证明报文正确的发送到了服务端,并收到了响应。
6.开50个线程跑10秒性能
tps达到了24420,可以认为java请求的方式本身没有性能瓶颈,能够作为压测的手段。tps可以更高,因为我的模拟服务端是本地的springboot服务,往console控制台打日志了,对效率也有影响。
java请求参数
java请求参数
在java请求页面,可以看到发送参数,下面演示如何个性化设置发送参数。
添加测试类
public class HelloJsonArgSample extends AbstractJavaSamplerClient {
private AtomicInteger counter = new AtomicInteger(0);
private JSONObject template = new JSONObject();
@Override
public void setupTest(JavaSamplerContext context) {
template.put("name", "HelloJsonSample");
template.put("version", "1.0.0");
}
@Override
public Arguments getDefaultParameters() {
Arguments arguments = new Arguments();
arguments.addArgument("url", "http://localhost:8081/post");
arguments.addArgument("key1", "value1");
return arguments;
}
@Override
public void teardownTest(JavaSamplerContext context) {
super.teardownTest(context);
}
public SampleResult runTest(JavaSamplerContext javaSamplerContext) {
int count = counter.incrementAndGet();
template.put("count", count);
String val = javaSamplerContext.getParameter("key1");
template.put("key1", val);
SampleResult sampleResult = new SampleResult();
HttpResponse httpResponse = null;
String body = template.toJSONString();
String url = javaSamplerContext.getParameter("url");
sampleResult.setSamplerData(body);
try {
sampleResult.sampleStart();
httpResponse = HttpRequest.post(url).body(body).timeout(60000).execute();
sampleResult.sampleEnd();
} catch (Exception e) {
e.printStackTrace();
sampleResult.sampleEnd();
sampleResult.setSuccessful(false);
sampleResult.setResponseMessage(e.getMessage());
return sampleResult;
}
String resBody = httpResponse.body();
// 解析返回报文
JSONObject resJson = JSON.parseObject(resBody);
String code = resJson.getString("code");
String retMsg = resJson.getString("retMsg");
sampleResult.setResponseCode(code);
sampleResult.setResponseMessage(retMsg);
sampleResult.setResponseData(httpResponse.bodyBytes());
sampleResult.setSentBytes(httpResponse.bodyBytes().length);
if(!Objects.equals("000000", code)) {
sampleResult.setSuccessful(false);
} else {
sampleResult.setSuccessful(true);
}
return sampleResult;
}
}
a.重载了getDefaultParameters方法
b.修改了runTest中url的获取方式
重新打包测试
关闭jmeter,重新打包,启动jmeter,添加新的线程组和java request。
可以看到,那两个参数能够在界面上看见了。
发送一笔请求,测试正常。
动态修改参数
这里的参数支持动态修改:
将value1改成value2:
但当我们切换java类时,他会自动还原。这样方便我们不修改java代码,动态调整基础参数。
CSV参数文件读取
读取csv文件测试
编写测试类
public class HelloJsonCsvSample extends AbstractJavaSamplerClient {
private AtomicInteger counter = new AtomicInteger(0);
private JSONObject template = new JSONObject();
@Override
public void setupTest(JavaSamplerContext context) {
template.put("name", "HelloJsonSample");
template.put("version", "1.0.0");
}
@Override
public Arguments getDefaultParameters() {
Arguments arguments = new Arguments();
arguments.addArgument("url", "http://localhost:8081/post");
arguments.addArgument("key1", "value1");
return arguments;
}
@Override
public void teardownTest(JavaSamplerContext context) {
super.teardownTest(context);
}
public SampleResult runTest(JavaSamplerContext javaSamplerContext) {
int count = counter.incrementAndGet();
template.put("count", count);
String val = javaSamplerContext.getParameter("key1");
template.put("key1", val);
// csv变量
String person = javaSamplerContext.getJMeterVariables().get("person");
String age = javaSamplerContext.getJMeterVariables().get("age");
template.put("person", person);
template.put("age", age);
SampleResult sampleResult = new SampleResult();
HttpResponse httpResponse = null;
String body = template.toJSONString();
String url = javaSamplerContext.getParameter("url");
sampleResult.setSamplerData(body);
try {
sampleResult.sampleStart();
httpResponse = HttpRequest.post(url).body(body).timeout(60000).execute();
sampleResult.sampleEnd();
} catch (Exception e) {
e.printStackTrace();
sampleResult.sampleEnd();
sampleResult.setSuccessful(false);
sampleResult.setResponseMessage(e.getMessage());
return sampleResult;
}
String resBody = httpResponse.body();
// 解析返回报文
JSONObject resJson = JSON.parseObject(resBody);
String code = resJson.getString("code");
String retMsg = resJson.getString("retMsg");
sampleResult.setResponseCode(code);
sampleResult.setResponseMessage(retMsg);
sampleResult.setResponseData(httpResponse.bodyBytes());
sampleResult.setSentBytes(httpResponse.bodyBytes().length);
if(!Objects.equals("000000", code)) {
sampleResult.setSuccessful(false);
} else {
sampleResult.setSuccessful(true);
}
return sampleResult;
}
}
a.在runTest方法里动态获取了参数person和age
关闭jmeter重新打包运行
一个线程跑两次:
可见读到了csv中的内容了。
扩展:分布式运行jmeter
有时候,jmeter客户端可能自身成为了一个瓶颈,比如在java请求中需要对报文做加解密等耗费CPU资源的操作,这时候可以考虑分布式运行jmeter。
官方说明:
Apache JMeter - Apache JMeter Distributed Testing Step-by-step
具体操作步骤:
为了演示方便,下面都是在本机windows上操作的,在linux上原理一样,只是把.bat后缀去掉。
1.把原jmeter复制三份
分别作为master(主控节点)、slave slave2(服务节点)
其中主控节点用于拉起压测,服务节点用于运行压测。
2.修改jmeter.properties
修改master的jmeter.properties配置,在最下方加上这几张
# 可以直接按ip和端口指定,或只指定host,端口默认就是1099了
remote_hosts=localhost:1199,localhost:1299
#server_port=1099
server.rmi.ssl.disable=true
特别关键的一步:server_port=1099这个要在master上注掉,因为我这里不想让他作为服务节点,而只是主控节点,不让他占用1099端口。
修改slave:
server_port=1199
server.rmi.ssl.disable=true
server.rmi.localport=0
指定了jmeter服务节点的端口是1199,他通过这个端口接收master发出的任务。
修改slave2:
server_port=1299
server.rmi.ssl.disable=true
server.rmi.localport=0
设置他的端口是1299。
这样就配置好了。
3.启动服务节点
双击运行slave和slave2下的命令:jmeter-server.bat
25881、25916是他的localport,不用管。
4.启动master GUI界面并测试
运行master的jmeter.bat启动GUI界面:
以java hello world为例,运行压测(这个示例属于空跑,内部sleep1毫秒):
10线程运行10秒:
只运行1199这个服务节点试下:
这个是1199对应的服务控制台打印的日志,表示接收到了master的任务并运行了。
tps为619
再两个都启动试下:
TPS为1237,大概是619的两倍。
注意事项
1.为了测试方便,每次运行前清理上次运行结果,右侧那两个扫把样子的图标,一个是清理选中的测试结果,一个是清理所有的测试结果。一般清理所有的即可。
2.快速启用禁用组件,比如查看结果树,可能会占用点资源,那么在正式测试时,可以将其禁用。也可以鼠标右键选择enable disable。
原文地址:https://blog.csdn.net/brimsullowr/article/details/144339277
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!