Bootstrap

JMeter实战技巧:使用Java Request Sampler进行接口测试

在现代软件开发中,接口测试是确保系统稳定性和可靠性的重要环节。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进行接口测试时提供有价值的参考。

;