我原来是做移动端测试工作的,后来接触了服务端,做了一套接口测试的执行器,
所有用例都是 json 串,并且所有的用例依赖关系也处理了(用例间的依赖,数据库依赖,缓存依赖,自定义方法),下面为阉割版:
{
"projectName": "Demo",
"testSetList": [
{
"testCaseList": [
{
"caseInfo": {
"caseName": "login",
"caseOwner": "lishu",
"caseComment": "登录-胡斐"
}
}
]
},
{
"testCaseList": [
{
"caseInfo": {
"caseComment": "雪山飞狐",
"caseName": "批发新款-提交"
}
}
]
},
{
"testCaseList": [
{
"caseInfo": {
"caseComment": "雪山飞狐",
"caseName": "现货批发-增补供应商"
}
},
{
"caseInfo": {
"caseComment": "雪山飞狐",
"caseName": "现货批发-下单"
}
}
]
},
{
"testCaseList": [
{
"caseInfo": {
"caseComment": "雪山飞狐",
"caseName": "翻单-增补供应商"
}
},
{
"caseInfo": {
"caseComment": "雪山飞狐",
"caseName": "下单审核-查询"
}
},
{
"caseInfo": {
"caseComment": "雪山飞狐",
"caseName": "下单审核-不通过"
}
}
]
},
{
"testCaseList": [
{
"caseInfo": {
"caseComment": "雪山飞狐",
"caseName": "现货批发-修改订单"
}
}
]
},
{
"testCaseList": [
{
"caseInfo": {
"caseComment": "雪山飞狐",
"caseName": "下单审核-通过"
}
}
]
},
{
"testCaseList": [
{
"caseInfo": {
"caseComment": "雪山飞狐",
"caseName": "文案任务-提交"
}
},
{
"caseInfo": {
"caseComment": "雪山飞狐",
"caseName": "商品列表-试穿"
}
}
]
}
]
}
后来有一位同事跟我说,我实现的功能,在 jmeter 中都有。。。
后来就看了 jmeter 的知识,确实,jmeter 很强大,就是感觉操作起来不太爽,调试起来不方便。
所以我也没有放弃对我的执行器的维护,但是一直有一个想法,就是如何让 jmeter 执行我的 json 串?
所以,我的目标是:让性能测试能与现有的接口测试用例共用一套用例,基于我的 json 串。
自己动手实践了一下 jmx 文件下 JavaSample,又踩了几个坑,最后实际是综合了上面两个,定下了方案:
编写一个 jmx 文件作为模板,该 jmx 文件作为执行器,其中包含一个 JavaSample 请求,
该 JavaSample 请求动态从 json 中获取用例并执行,所有的用例间依赖关系,采用自己设计接口测试执行器中的方案,
即我的接口自动化一期。
jmeter 5.1.1
pom 依赖
<properties>
<okhttp3.version>3.10.0</okhttp3.version>
<fastjson.version>1.2.47</fastjson.version>
<assertj.version>3.8.0</assertj.version>
<lombok.version>1.16.18</lombok.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_core</artifactId>
<version>5.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_java</artifactId>
<version>5.1.1</version>
</dependency>
<dependency>
<groupId>com.lazerycode.jmeter</groupId>
<artifactId>jmeter-maven-plugin</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp3.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>${okhttp3.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>com.wz</groupId>
<artifactId>harConvert</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>assembly</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
import apiTestModel.ApiTestCase;
import com.wz.exec.JSONExecutor;
import com.wz.utils.ApiTestUtils;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;
public class MyJavaSample extends AbstractJavaSamplerClient {
@Override
public SampleResult runTest(JavaSamplerContext javaSamplerContext) {
ApiTestCase apiTestCase = ApiTestUtils.getOne();
javaSamplerContext.getJMeterContext().getCurrentSampler().setName(apiTestCase.getCaseInfo().getCaseName());
JSONExecutor jsonExecutor = new JSONExecutor(apiTestCase);
SampleResult sampleResult = new SampleResult();
sampleResult.sampleStart();
jsonExecutor.run();
sampleResult.sampleEnd();
apiTestCase = ApiTestUtils.getCurrentTestCase();
sampleResult.setSamplerData(apiTestCase.getTestResult().getReqBody());
sampleResult.setSuccessful(true);
sampleResult.setResponseCode("200");
sampleResult.setResponseMessage(apiTestCase.getTestResult().getResBody());
ApiTestUtils.setApiTestResult(ApiTestUtils.getCurrentTestCase());
return sampleResult;
}
}
import apiTestModel.*;
import com.alibaba.fastjson.JSON;
import org.apache.commons.collections4.iterators.LoopingIterator;
import org.apache.commons.io.FileUtils;
import org.apache.jmeter.threads.JMeterContextService;
import org.apache.jmeter.util.JMeterUtils;
import java.io.File;
import java.io.IOException;
import java.util.*;
public final class ApiTestUtils {
private static List<ApiTestCase> apiTestCaseList = new ArrayList<>();
private static ThreadLocal<LoopingIterator<ApiTestCase>> apiTestCaseLoopingIterator = new ThreadLocal<>();;
private static ThreadLocal<ApiTestCase> apiTestCase = new ThreadLocal<>();
private static ThreadLocal<Map<String, ApiTestCase>> resultMap = new ThreadLocal<>();
private static ApiTestProject apiTestProject;
private static ThreadLocal<Map<String, Object>> globalHeaders = new ThreadLocal<>();
private ApiTestUtils() {
}
static {
String JSONFilePath = JMeterContextService.getContext().getProperties().getProperty("JSONFilePath");
System.out.println("JSONFilePath:" + JSONFilePath);
System.out.println("ApiTestUtils static run start");
String apiTestProjectStr;
try {
apiTestProjectStr = FileUtils.readFileToString(new File(JSONFilePath), "UTF-8");
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Read the json file failed:" + JSONFilePath);
}
apiTestProject = JSON.parseObject(apiTestProjectStr, ApiTestProject.class);
if (apiTestProject.getGlobalHeaderMap() == null) {
apiTestProject.setGlobalHeaderMap(new HashMap<>());
}
if (apiTestProject.getGlobalParameters() == null) {
GlobalParameters globalParameters = new GlobalParameters();
globalParameters.setGlobalParametersMap(new HashMap<>());
}
for (ApiTestSet apiTestSet : apiTestProject.getTestSetList()) {
for (ApiTestCase testCase : apiTestSet.getTestCaseList()) {
ApiTestResult apiTestResult = new ApiTestResult();
testCase.setTestResult(apiTestResult);
apiTestCaseList.add(testCase);
}
}
System.out.println("ApiTestUtils static run finished");
}
public static ApiTestCase getOne() {
if (apiTestCaseLoopingIterator.get() == null) {
apiTestCaseLoopingIterator.set(new LoopingIterator<>(apiTestCaseList));
}
apiTestCase.set(apiTestCaseLoopingIterator.get().next());
return apiTestCase.get();
}
public static ApiTestCase getCurrentTestCase() {
return apiTestCase.get();
}
public static void setCurrentTestCase(ApiTestCase testCase) {
apiTestCase.set(testCase);
}
public static void setApiTestResult(ApiTestCase apiTestCase) {
if (resultMap.get() == null) {
resultMap.set(new HashMap<String, ApiTestCase>());
} else {
resultMap.get().put(apiTestCase.getCaseInfo().getCaseName(), apiTestCase);
}
}
public static Map<String, Object> getGlobalHeaders() {
if (globalHeaders.get() == null) {
globalHeaders.set(new HashMap<String, Object>());
}
return globalHeaders.get();
}
public static ApiTestCase getTestCase(String caseName) {
return resultMap.get().get(caseName);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "--" + getOne().getCaseInfo().getCaseName());
System.out.println(Thread.currentThread().getName() + "--" + getOne().getCaseInfo().getCaseName());
System.out.println(Thread.currentThread().getName() + "--" + getOne().getCaseInfo().getCaseName());
}
};
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
t1.start();
t2.start();
}
public static ApiTestUtils getInstance() {
return Instance.instance;
}
private static class Instance {
private static ApiTestUtils instance;
static {
instance = new ApiTestUtils();
}
}
}
// JMeter const variable
String constVariable = JMeterContextService.getContext().getVariables().get("constVariable");
System.out.println("constVariable:" + constVariable);
// JMeter property, use -J propName=propValue in shell/dos
String JSONFilePath = JMeterContextService.getContext().getProperties().getProperty("JSONFilePath");
System.out.println("JSONFilePath:" + JSONFilePath);
目前基本上算是踩坑完成,看结果,我只有一个 JavaSample
上周六请了一天假去阿里西溪园参加性能测试的活动,可惜去之前也没做什么准备,听的我还是有点懵的,
接下来就是主要是整个 RPS 的实践,最好能发现开发的问题,并修改验证
下载地址:https://jmeter-plugins.org/downloads/old/