在现代软件开发中,接口测试是确保系统稳定性和可靠性的重要环节。JMeter是一款开源的负载测试工具,它支持多种协议和数据格式,能够模拟大量用户并发访问,从而对系统进行压力测试。本文将介绍如何使用JMeter的Java Request Sampler进行接口测试,并分享一些实战技巧。
1. 什么是Java Request Sampler?
Java Request Sampler是JMeter提供的一种扩展机制,允许开发者通过编写Java代码来自定义请求行为。这使得我们可以灵活地实现各种复杂的测试场景,比如调用RESTful API、数据库操作等。
Java Request 实现知识点
❖ Java Request 执⾏类必须继承 AbstractJavaSamplerClient 抽象类
❖ 各种 Post Get Delete 请求需要使⽤ java 的 HttpClient 来实现
❖ 接⼝请求之间的交互在java 代码中来控制
❖ HttpResponse 中的Json 返回值解析使⽤ java 中的 json 解析库来进⾏解析
❖ 除了最终的运⾏和数据交互需要进⼊jmeter,基本上已经俨然变成了java 程序开发活动
2. 环境准备
2.1 安装JMeter
首先,我们需要下载并安装JMeter。可以从Apache JMeter官网下载最新版本。
2.2 添加依赖
为了使用HttpClient和JSONParser,我们需要在项目中添加相应的依赖。假设我们使用的是Maven项目,可以在pom.xml
文件中添加以下依赖:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test.demo</groupId>
<artifactId>jmeter_java</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>jmeter_java</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.0.0.RELEASE</spring.version>
<hibernate.version>4.3.0.Final</hibernate.version>
<osjdk.version>3.2.1</osjdk.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_java</artifactId>
<version>5.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_core</artifactId>
<version>5.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20080701</version>
</dependency>
</dependencies>
<build>
<finalName>jmeter_java</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<configuration>
<tasks>
<copy todir="${env.jmeter_path}/lib/ext">
<fileset dir="${project.build.directory}">
<include name="jmeter_java.jar" />
</fileset>
</copy>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2.3 添加jmeter依赖
JMeter依赖配置,需要将 iJava_Request/jars/json-20080701.jar 复制/粘贴到 <jmeter_path>/lib/ext
java request 程序 jar包存放位置 <jmeter_path>/lib/ext
3. 编写Java Request Sampler类
接下来,我们编写一个继承自AbstractJavaSamplerClient
的类,实现接口测试逻辑。
package com.test.stress;
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.apache.jmeter.threads.JMeterVariables;
import com.test.common.HttpClient;
import com.test.utils.JSONParser;
import java.io.Serializable;
public class JHttpRequestSample extends AbstractJavaSamplerClient implements Serializable {
@Override
public Arguments getDefaultParameters() {
Arguments params = new Arguments();
params.addArgument("hostname", "default_host");
return params;
}
@Override
public void setupTest(JavaSamplerContext context) {
super.setupTest(context);
System.out.println("==== RestfulAPI test started! ====");
}
@Override
public void teardownTest(JavaSamplerContext context) {
super.teardownTest(context);
System.out.println("==== RestfulAPI test stopped. ====");
}
@Override
public SampleResult runTest(JavaSamplerContext arg0) {
JMeterVariables jMeterVariables = arg0.getJMeterVariables();
String port = jMeterVariables.get("port");
String username = jMeterVariables.get("username");
String password = jMeterVariables.get("password");
String hostname = arg0.getParameter("hostname");
System.out.println("== JMeter Variables ==");
System.out.println("hostname = " + hostname);
System.out.println("port = " + port);
System.out.println("username = " + username);
System.out.println("password = " + password);
System.out.println("== Test start with user " + username + " ==");
SampleResult sampleResult = new SampleResult();
sampleResult.sampleStart();
boolean testResult = menuRestfulAPITest(hostname, port, username, password);
if (testResult) {
sampleResult.setSuccessful(true); //设定成功条件下的 Java Request Sampler 结果为成功
String succMsg = "OrderService restfulAPI test success.";
System.out.println(succMsg);
sampleResult.setResponseData(succMsg.getBytes());
} else {
sampleResult.setSuccessful(false); //设定失败条件下的 Java Request Sampler 结果为失败
String failMsg = "OrderService restfulAPI test failed.";
System.out.println(failMsg);
sampleResult.setResponseData(failMsg.getBytes());
}
sampleResult.sampleEnd();
return sampleResult;
}
public static boolean menuRestfulAPITest(String hostname, String port, String username, String password) {
String protocal = "http";
String access_token = "";
//接口1 登录操作
String path1 = "/api/v1/user/login";
String url1 = protocal + "://" + hostname + ":" + port + path1;
String reqData1 = "{\n" +
"\t\"authRequest\": {\n" +
"\t\t\"userName\": \"" + username + "\",\n" +
"\t\t\"password\": \"" + password + "\"\n" +
"\t}\n" +
"}";
String respData1 = HttpClient.sendPost(url1, reqData1, access_token);
access_token = JSONParser.getJsonValue(respData1, "access_token");
String retcode1 = JSONParser.getJsonValue(respData1, "code");
if (!"200".equalsIgnoreCase(retcode1)) { //校验接口1的返回code是否等于200
System.out.println("1. 登录接口请求失败! return code = " + retcode1);
return false;
}
System.out.println("1. 登录接口请求成功");
//接口2 浏览菜单
String path2 = "/api/v1/menu/list";
String url2 = protocal + "://" + hostname + ":" + port + path2;
String respData2 = HttpClient.sendGet(url2, access_token);
String retcode2 = JSONParser.getJsonValue(respData2, "code");
if (!"200".equalsIgnoreCase(retcode2)) { //校验接口2的返回code是否等于200
System.out.println("2. 浏览菜单接口请求失败" + " return code = " + retcode2);
return false;
}
System.out.println("2. 浏览菜单接口请求成功");
//接口3 下订单
String path3 = "/api/v1/menu/confirm";
String url3 = protocal + "://" + hostname + ":" + port + path3;
String reqData3 = "{\n" +
" \"order_list\": [\n" +
" {\n" +
" \"menu_nuumber\" : \"01\",\n" +
" \"number\" : 1\n" +
" },\n" +
" {\n" +
" \"menu_nuumber\" : \"03\",\n" +
" \"number\" : 2\n" +
" }\n" +
" ]\n" +
"}";
String respData3 = HttpClient.sendPost(url3, reqData3, access_token);
String retcode3 = JSONParser.getJsonValue(respData3, "code");
if (!"200".equalsIgnoreCase(retcode3)) { //校验接口3的返回code是否等于200
System.out.println("3. 下订单接口请求失败" + " return code = " + retcode3);
return false;
}
System.out.println("3. 下订单接口请求成功");
//接口4 退出
String path4 = "/api/v1/user/logout";
String url4 = protocal + "://" + hostname + ":" + port + path4;
String respData4 = HttpClient.sendDelete(url4, access_token);
String retcode4 = JSONParser.getJsonValue(respData4, "code");
if (!"200".equalsIgnoreCase(retcode4)) { //校验接口4的返回code是否等于200
System.out.println("4. 退出接口请求成功" + " return code = " + retcode4);
return false;
}
System.out.println("4. 退出接口请求成功");
return true;
}
}
4. 配置JMeter测试计划
4.1 添加线程组
在JMeter中添加一个线程组,设置线程数、Ramp-Up时间和循环次数。例如,设置10个线程,Ramp-Up时间为5秒,循环次数为1次。
4.2 添加Java Request Sampler
在线程组下添加一个Java Request Sampler,配置如下:
- Classname:
com.test.stress.JHttpRequestSample
- Parameters: 根据需要填写参数,如
hostname=localhost
,port=9091
,username=user01
,password=pwd
。
4.3 添加User Defined Variables
在线程组下添加一个User Defined Variables,配置如下:
4.4 添加CSV Data Set Config
在线程组下添加一个CSV Data Set Config,配置如下:
4.3 添加监听器
添加一个查看结果树(View Results Tree)监听器,以便查看每个请求的详细结果。
5. 运行测试并分析结果
启动JMeter测试计划,观察查看结果树中的请求响应情况。重点关注每个接口的返回码和响应时间,以评估系统性能。如果某个接口的返回码不是200,或者响应时间过长,说明可能存在性能瓶颈或错误。
6. 总结与优化建议
通过上述步骤,我们可以使用JMeter进行接口测试,并通过Java Request Sampler实现复杂的业务逻辑。以下是一些优化建议:
- 参数化测试数据:使用CSV Data Set Config元件读取外部文件,实现多组测试数据的自动化测试。
- 断言:使用响应断言(Response Assertion)验证接口返回的数据是否符合预期。
- 日志记录:在Java代码中增加详细的日志记录,便于问题排查。
- 性能监控:结合JMeter的聚合报告(Aggregate Report)和图形结果(Graph Results)等监听器,全面分析系统性能。
通过不断迭代和优化,可以逐步提升系统的稳定性和性能。希望本文能为你在使用JMeter进行接口测试时提供有价值的参考。