文章目录
1、Jmeter自定义取样器扩展类
Jmeter提供默认界面(AbstractJavaSamplerClient)和自定义界面的(AbstractSamplerGui)两种自定义取样器的插件开发方式,对于复杂的压测任务,可以通过自定义取样器的方式来实现。
本文通过压测SpringBoot的http接口演示两个自定义扩展类的实现方式:
2、SpringBoot服务器端http测试例子
maven项目工程,pom.xml
<?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.penngo.example</groupId>
<artifactId>gateway-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>gateway-service</name>
<description>https://blog.csdn.net/penngo</description>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<java.version>11</java.version>
<spring-boot.version>2.7.2</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.penngo.example.service.Service2App</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
http接口示例代码,Service2App.java
package com.penngo.example.service;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@SpringBootApplication
public class Service2App {
public static void main(String[] args) {
SpringApplication.run(Service2App.class, args);
}
@RestController
public class HelloController {
@GetMapping("/test")
public Map test(HttpServletRequest request){
String page = request.getParameter("page");
String keyword = request.getParameter("keyword");
String userid = "";
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for(Cookie cookie:cookies){
if(cookie.getName().equals("userid")){
userid = cookie.getValue();
break;
}
}
}
Map<String, String> data = new HashMap<>();
data.put("page", page);
data.put("keyword", keyword);
data.put("userid", userid);
return data;
}
}
}
3、自定义取样器实现
两种扩展的实现代码都在同一个maven工程里面,pom.xml代码:
<?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.test.jmeter</groupId>
<version>1.0.0</version>
<artifactId>jmter_test</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.2</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.5</version>
</dependency>
<!-- 注意与Jmeter的版本一致 -->
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_core</artifactId>
<version>5.4.3</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_java</artifactId>
<version>5.4.3</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
</dependency>
</dependencies>
</project>
3.1、默认界面的AbstractJavaSamplerClient扩展实现
可通过getDefaultParameters()接口,实现在默认界面上配置参数,SampleResult负责记录样本结果,TestHttpSampler.java代码:
package com.test.jmeter;
import cn.hutool.json.JSONUtil;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class TestHttpSampler extends AbstractJavaSamplerClient {
private static final Logger log = LoggerFactory.getLogger(TestHttpSampler.class);
@Override
public SampleResult runTest(JavaSamplerContext javaSamplerContext) {
String url = javaSamplerContext.getParameter("url");
String userid = javaSamplerContext.getParameter("userid");
Map<String, String> cookieMap = new HashMap();
cookieMap.put("userid", userid);
SampleResult sampleResult = new SampleResult();
sampleResult.setSampleLabel("JavaSamplerClient请求查询");
sampleResult.sampleStart();
try {
Map<String, String> data = data();
sampleResult.setRequestHeaders(JSONUtil.toJsonStr(data));
var res = Jsoup.connect(url)
.header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
.ignoreContentType(true)
.cookies(cookieMap)
.data(data)
.method(Connection.Method.GET)
.execute();
String body = res.body();
log.info(body);
sampleResult.setSuccessful(true);
sampleResult.setResponseCode("200");
sampleResult.setResponseData(body, "UTF-8");
sampleResult.setResponseCodeOK();
}
catch(Exception e){
log.error("runTest error:",e);
sampleResult.setResponseCode("500");
sampleResult.setSuccessful(false);
sampleResult.setResponseData("exception," + e.getMessage(), "UTF-8");
}
sampleResult.sampleEnd();
return sampleResult;
}
private Map<String, String> data(){
Random r = new Random();
String page = String.valueOf((r.nextInt(5) + 1));
StringBuffer keyword = new StringBuffer();
String str = "abcdefghijklmnopqrstuvwxyz";
for(int i = 0; i < 7; i++){
keyword.append(str.toCharArray()[r.nextInt(str.length())]);
}
Map<String, String> data = new HashMap<>();
data.put("page",page);
data.put("keyword",keyword.toString());
return data;
}
public Arguments getDefaultParameters() {
Arguments arguments = new Arguments();
arguments.addArgument("url", "");
arguments.addArgument("userid", "");
return arguments;
}
}
3.2、自定义界面的AbstractSamplerGui扩展实现
自定义界面的UI库是基于swing,可以使用所有的swing组件
package com.test.jmeter;
import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
import org.apache.jmeter.testelement.TestElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import java.awt.*;
public class TestGuiHttpSampler extends AbstractSamplerGui {
private static final Logger log = LoggerFactory.getLogger(TestGuiHttpSampler.class);
private JTextField urlField = null;
private JTextField useridField = null;
public TestGuiHttpSampler(){
urlField = new JTextField();
useridField = new JTextField();
initUI();
}
private void initUI(){
JPanel topPanel = new JPanel(new GridBagLayout());
topPanel.add(new JLabel("http参数"), new GB(0,0,1,1).setInsets(5));
topPanel.add(new JLabel("访问地址:"), new GB(0,1,1,1).setInsets(5));
topPanel.add(urlField, new GB(1,1,1,1).setInsets(5).setFill(GB.BOTH).setWeight(100,0));
topPanel.add(new JPanel(), new GB(0,2,2,1).setInsets(5).setFill(GB.BOTH).setWeight(100,100));
JPanel bottomPanel = new JPanel(new GridBagLayout());
bottomPanel.add(new JLabel("Cookie参数"), new GB(0,0,1,1).setInsets(5));
bottomPanel.add(new JLabel("用户id:"), new GB(0,1,1,1).setInsets(5));
bottomPanel.add(useridField, new GB(1,1,1,1).setInsets(5).setFill(GB.BOTH).setWeight(100,0));
bottomPanel.add(new JPanel(), new GB(0,2,2,1).setInsets(5).setFill(GB.BOTH).setWeight(100,100));
JSplitPane splitPane = new JSplitPane();
splitPane.setOneTouchExpandable(true);
splitPane.setContinuousLayout(true);
log.info("====TestGuiHttpSampler size:" + this.getSize());
splitPane.setDividerLocation(50);
splitPane.setPreferredSize(this.getSize());
splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
splitPane.setTopComponent(topPanel);
splitPane.setBottomComponent(bottomPanel);
setLayout(new BorderLayout());
add(splitPane, BorderLayout.CENTER);
}
@Override
public String getLabelResource() {
return null;
}
@Override
public TestElement createTestElement() {
TestGuiSampler sample = new TestGuiSampler();
return sample;
}
@Override
public void modifyTestElement(TestElement testElement) {
testElement.clear();
configureTestElement(testElement);
testElement.setProperty(TestGuiSampler.URL, urlField.getText());
testElement.setProperty(TestGuiSampler.USERID, useridField.getText());
}
@Override
public boolean canBeAdded() {
return super.canBeAdded();
}
@Override
public String getStaticLabel() {
return "TestGuiHttpSampler测试";
}
@Override
public void clearGui() {
super.clearGui();
urlField.setText("");
useridField.setText("");
}
}
3、自定义取样器运行效果
工程项目打包,把jmter_test-1.0.0.jar、jsoup-1.15.2.jar、hutool-all-5.8.5.jar三个包扔到apache-jmeter-5.4.3\lib\ext目录中,重新启动Jmeter。
3.1、AbstractJavaSamplerClient运行效果
在线程组上鼠标右键,弹出菜单中选择“取样器->Java请求中”,在面板的下拉框中可以看到实现的扩展类名并选择。
3.2、AbstractSamplerGui运行效果
在线程组上右键,在取样器的子菜单中,能看到实现的扩展类"TestGuiHttpSampler测试",选择即可