一、前言
在上一篇博客中,小编向大家简单介绍了jmeter 的GUI界面的压测使用步骤,通过这个步骤我们可以应付大部分的压测问题了。很多接口都可以通过这种方式来得到压测报告,根据压测报告的数据来分析线上真正要使用多少台机器。
但是有的时候,我们需要多个接口连起来测一个流程,如果使用简单的GUI界面,就不能完成这个任务了,所以我们可以使用jmeter提供的ApacheJMeter_core.jar和ApacheJMeter_java.jar来编写自定义的测试流程。
下面就简单的介绍一下。
二、建立maven项目
添加maven依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.soybean</groupId>
<artifactId>redpacketJmeter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_java</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_java</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.37</version>
</dependency>
<dependency>
<groupId>com.soybean</groupId>
<artifactId>base-utils</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- 用于打可执行jar包 -->
<!-- 打包jar文件时,配置manifest文件,加入lib包的jar依赖 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<classesDirectory>target/classes/</classesDirectory>
<archive>
<manifest>
<!-- 主函数的入口 -->
<mainClass>com.soybean.Application</mainClass>
<!-- 打包时 MANIFEST.MF文件不记录的时间戳版本 -->
<useUniqueVersions>false</useUniqueVersions>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<type>jar</type>
<includeTypes>jar</includeTypes>
<!--<useUniqueVersions>false</useUniqueVersions> -->
<outputDirectory>
${project.build.directory}/lib
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
三、建立执行类
新建一个类,类名为BaseJmeterHttp,该类继承AbstractJavaSamplerClient类,AbstractJavaSamplerClient存在于ApacheJMeter_java.jar这个JAR包中,引用即可调用。
BaseJmeterHttp类在继承AbstractJavaSamplerClient类的时候,需要实现四个方法,分别是
-
setupTest():初始化方法,用于初始化性能测试时的每个线程;
-
getDefaultParameters():主要用于设置传入的参数;
-
runTest():为性能测试时的线程运行体;
-
teardownTest():测试结束方法,用于结束性能测试中的每个线程。
具体代码:
package com.soybean.test.http;
import com.soybean.common.logger.DushuLogger;
import com.soybean.test.Entity.Packet;
import com.soybean.test.Entity.PacketShareUrlVO;
import com.soybean.test.util.HttpClientUtils;
import com.soybean.test.util.HttpResult;
import com.soybean.test.util.JsonUtil;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.threads.JMeterVariables;
import java.util.*;
import java.util.concurrent.*;
/**
* <br>
* Description: BaseJmeterHttpImpl<br>
* Company : *********科技有限公司 <br>
* Author : WangLei<br>
* Date : 2018/10/15 14:20<br>
* Modify : 修改日期 修改人员 修改说明 JIRA编号<br>
* v1.0.0 2018/10/15 WangLei 新增 1001<br>
********************************************************************/
public class BaseJmeterHttp extends AbstractJavaSamplerClient {
// private String ip ="http://gateway-java-bench.dushu.io";
private final String ip = "http://10.80.60.181:1111";
// 线程数
private final static int THREAD_SIZE = 30;
private final ExecutorService executorService = Executors.newFixedThreadPool(THREAD_SIZE);
@Override
public SampleResult runTest(JavaSamplerContext javaSamplerContext) {
Packet packet = new Packet();
JMeterVariables jMeterVariables = javaSamplerContext.getJMeterVariables();
Iterator<Map.Entry<String, Object>> iterator = jMeterVariables.getIterator();
while (iterator.hasNext()) {
Map.Entry<String, Object> entry = iterator.next();//把Object型强转成int型
DushuLogger.info("获取到的参数为:" + JsonUtil.toJSONObject(entry));
if (entry.getKey().equals("senderId")) {
packet.setUserId((String) entry.getValue());
}
if (entry.getKey().equals("orderNo")) {
packet.setOrderNo((String) entry.getValue());
}
if (entry.getKey().equals("token")) {
packet.setToken(entry.getValue().toString().split("-"));
}
if (entry.getKey().equals("getId")) {
packet.setGetterId(entry.getValue().toString().split("-"));
}
packet.setAppId("1001");
}
boolean flag = true;
String errorInfo = "";
SampleResult sr= new SampleResult();
List<Future<Integer>> futures = new ArrayList<>();
int countSuccess = 0;
try {
// 记录程序执行时间以及执行结果
sr.sampleStart();
DushuLogger.info("接收到的参数:" + JsonUtil.toJSON(packet));
DushuLogger.info("开始创建红包");
HttpResult httpResult = HttpClientUtils.postUrlAsJson(ip + "/redPacket-system/redPacket/generateRedPacket", JsonUtil.toJSONObject(packet));
if (!httpResult.isSuccess()) {
DushuLogger.error("调用生成红包接口失败");
errorInfo = "调用生成红包接口失败";
flag = false;
}
Map map = JsonUtil.fromJSON(httpResult.getResponse(), Map.class);
DushuLogger.info("创建红包返回结果:" + JsonUtil.toJSON(map));
if (map.get("data") == null || !"0000".equals(map.get("status"))) {
DushuLogger.error("创建红包失败");
errorInfo = "调用生成红包接口成功,但是处理失败:" + JsonUtil.toJSON(map) + " ,请求参数为:" + JsonUtil.toJSONObject(packet);
flag = false;
} else {
//领红包
final CountDownLatch latch = new CountDownLatch(THREAD_SIZE);
for (int i = 0; i < THREAD_SIZE; i++) {
PacketShareUrlVO packetShareUrlVO = new PacketShareUrlVO();
packetShareUrlVO.setRedPacketId(Long.parseLong(map.get("data").toString()));
packetShareUrlVO.setAppId(packet.getAppId());
packetShareUrlVO.setToken(packet.getToken()[i]);
packetShareUrlVO.setUserId(packet.getGetterId()[i]);
DushuLogger.info(JsonUtil.toJSON(packetShareUrlVO));
DushuLogger.info(packetShareUrlVO);
Callable<Integer> task1 = () -> {
String resultInfo = "";
//领红包
HttpResult httpResultSmall = HttpClientUtils.postUrlAsJson(ip + "/redPacket-system/redPacket/bindSmallPacketAndUser", JsonUtil.toJSONObject(packetShareUrlVO));
if (!httpResultSmall.isSuccess()) {
DushuLogger.error("【领红包失败】调用领红包接口失败:" + JsonUtil.toJSONObject(packetShareUrlVO));
resultInfo = "【领红包失败】调用领红包接口失败:" + JsonUtil.toJSONObject(packetShareUrlVO);
}
Map smallPacketMap = JsonUtil.fromJSON(httpResultSmall.getResponse(), Map.class);
if (smallPacketMap.get("status") == null || !"0000".equals(smallPacketMap.get("status"))) {
DushuLogger.error("【领红包失败】调用领红包接口成功,但是处理失败,入参为:" + JsonUtil.toJSONObject(packetShareUrlVO) + "处理结果为:" + JsonUtil.toJSONObject(smallPacketMap));
resultInfo = "【领红包失败】调用领红包接口成功,但是处理失败,入参为:" + JsonUtil.toJSONObject(packetShareUrlVO) + "处理结果为:" + JsonUtil.toJSONObject(smallPacketMap);
} else {
//更新会期
Map<String, Object> addVipParamMap = new HashMap<>();
addVipParamMap.put("token", packetShareUrlVO.getToken());
HttpResult addVipTermResult = HttpClientUtils.postUrlAsJson(ip + "/redPacket-system/redPacket/addVipTerm", addVipParamMap);
if (!addVipTermResult.isSuccess()) {
DushuLogger.error("【更新会期失败】调用更新会期接口失败:" + JsonUtil.toJSONObject(addVipParamMap));
resultInfo = "【更新会期失败】调用更新会期接口失败:" + JsonUtil.toJSONObject(addVipParamMap);
}
Map addVipMap = JsonUtil.fromJSON(addVipTermResult.getResponse(), Map.class);
if (addVipMap.get("status") == null || !"0000".equals(addVipMap.get("status"))) {
DushuLogger.error("【更新会期失败】调用更新会期接口成功,但是处理失败,入参:" + JsonUtil.toJSONObject(addVipParamMap) + "处理结果为:" + JsonUtil.toJSONObject(addVipMap));
resultInfo = "【更新会期失败】调用更新会期接口成功,但是处理失败,入参:" + JsonUtil.toJSONObject(addVipParamMap) + "处理结果为:" + JsonUtil.toJSONObject(addVipMap);
} else {
DushuLogger.info("更新会期成功");
}
}
latch.countDown();
return "".equals(resultInfo) ? 1 : 0;
};
futures.add(executorService.submit(task1));
}
latch.await();
}
//统计结果
for (Future f : futures) {
countSuccess = countSuccess + (int) f.get();
}
DushuLogger.info("【统计结果】一共抢红包的人有:" + THREAD_SIZE + "个,其中成功抢到红包的有:" + countSuccess + "个");
flag = countSuccess == 15;
if (!flag) {
errorInfo =errorInfo + "请求参数为:" + JsonUtil.toJSONObject(packet) +"【统计结果】一共抢红包的人有:" + THREAD_SIZE + "个,其中成功抢到红包的有:" + countSuccess + "个";
}
sr.setSuccessful(flag);
} catch (Exception e) {
sr.setSuccessful(false);
} finally {
sr.sampleEnd();
}
//将数据打印到查看结果树当中
sr.setResponseData(flag ? "红包流程执行成功,共有 " + countSuccess + " 个成功抢到红包,请求参数为:" + JsonUtil.toJSONObject(packet) : "红包流程执行失败,原因:" + errorInfo, null);
sr.setDataType(SampleResult.TEXT);
return sr;
}
}
四、Jmeter运行分析
1、将上述代码打包成jar包,生成的包名称为redpacketJmeter.jar,将jar包拷贝到Jmeter的安装目录lib/ext下面。
2、把依赖的jar包都拷贝到Jmeter安装目录的lib下,替换原有的同名jar包
2、运行Jmeter,添加线程组及java请求,显示如下:
3、添加监听器,这里我们添加查看结果树和聚合报告就好。
4、结果显示如下图:
五、小结
Jmeter是用java语言开发的,所以我们可以用java开发出代码,直接使用,当然其中还有一些参数是要用的,比如读取csv文件的内容等。希望大家可以学习到知识。
github源码:https://github.com/AresZone/JmeterCodeTest