循环、轮询提交

This commit is contained in:
liangdaliang
2025-02-20 15:42:10 +08:00
parent 1eabec1d74
commit 99200c7f63
18 changed files with 1289 additions and 30 deletions

View File

@@ -146,6 +146,11 @@
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.8.0</version>
</dependency>
</dependencies>

View File

@@ -0,0 +1,112 @@
package com.test.common.core.domain.model;
/**
* @author liangdaliang
* @DescriptionJmeter调用参数
* @date 2025-02-19 10:55
*/
public class JmeterRequest {
/**
* 用例步骤id
*/
private Long id;
/**
* 请求完整url
*/
private String url;
/**
* 请求端口号
*/
private int port;
/**
* 请求方式
*/
private String method;
/**
* 请求body
*/
private String requestBody;
/**
* 请求参数url?后面的参数
*/
private String requestParams;
/**
* 请求头Json
*/
private String requestHeader;
/**
* jmeter安装home路径
*/
private String jmeterHomePath;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getRequestBody() {
return requestBody;
}
public void setRequestBody(String requestBody) {
this.requestBody = requestBody;
}
public String getRequestParams() {
return requestParams;
}
public void setRequestParams(String requestParams) {
this.requestParams = requestParams;
}
public String getRequestHeader() {
return requestHeader;
}
public void setRequestHeader(String requestHeader) {
this.requestHeader = requestHeader;
}
public String getJmeterHomePath() {
return jmeterHomePath;
}
public void setJmeterHomePath(String jmeterHomePath) {
this.jmeterHomePath = jmeterHomePath;
}
}

View File

@@ -2,6 +2,9 @@ package com.test.common.utils;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import com.test.common.core.domain.model.JmeterRequest;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.config.gui.ArgumentsPanel;
import org.apache.jmeter.control.LoopController;
@@ -54,16 +57,18 @@ public class JMeterUtil {
/**
* 生成jmeter测试执行计划并获取执行结果
* @param id
* @param url
* @param port
* @param method
* @param paramJson
* @param requestHeader
* @param jmeterHomePath
* @param jmeterRequest
* @return
*/
public static Map<String, String> getJmeterResult(Long id, String url, int port, String method, String paramJson, String requestHeader, String jmeterHomePath) {
public static Map<String, String> getJmeterResult(JmeterRequest jmeterRequest) {
Long id = jmeterRequest.getId();
String url = jmeterRequest.getUrl();
int port = jmeterRequest.getPort();
String method = jmeterRequest.getMethod().toUpperCase();
String requestBody = jmeterRequest.getRequestBody();
String requestParams = jmeterRequest.getRequestParams();
String requestHeader = jmeterRequest.getRequestHeader();
String jmeterHomePath = jmeterRequest.getJmeterHomePath();
Map<String, String> result = null;
try {
// 1. 初始化 JMeter
@@ -83,13 +88,14 @@ public class JMeterUtil {
httpSampler = createPostHttpSampler(
url, // 请求地址
port,
paramJson // 请求参数
requestBody, // 请求
requestParams // 查询参数
);
} else {
httpSampler = createGetHttpSampler(
url, // 请求地址
port,
paramJson // 请求参数
requestParams // 查询参数
);
}
// 5. 创建请求头管理器
@@ -189,11 +195,11 @@ public class JMeterUtil {
* 创建get请求方式
* @param urlString
* @param port
* @param requestJson
* @param requestParams
* @return
* @throws MalformedURLException
*/
private static HTTPSamplerProxy createGetHttpSampler(String urlString, int port, String requestJson) throws MalformedURLException {
private static HTTPSamplerProxy createGetHttpSampler(String urlString, int port, String requestParams) throws MalformedURLException {
URL url = new URL(urlString);
// 提取域名(不包括端口号)
String domain = url.getHost();
@@ -204,6 +210,9 @@ public class JMeterUtil {
httpSampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
httpSampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
httpSampler.setDomain(domain); // 提取域名
if (!StringUtils.isEmpty(requestParams)) {
path = path + "?" + requestParams;
}
httpSampler.setPath(path); // 提取路径
httpSampler.setPort(port);
httpSampler.setMethod("GET");
@@ -211,17 +220,17 @@ public class JMeterUtil {
httpSampler.setUseKeepAlive(true);
// 添加请求参数
Map<String, String> parameters = new HashMap<>();
if (!StringUtils.isEmpty(requestJson)) {
Gson gson = new Gson();
// 定义 Map 的类型
Type type = new TypeToken<Map<String, String>>() {}.getType();
// 将 JSON 字符串转换为 Map
parameters = gson.fromJson(requestJson, type);
path += "?";
path += mapToQueryString(parameters);
httpSampler.setPath(path); // 提取路径
}
// Map<String, String> parameters = new HashMap<>();
// if (!StringUtils.isEmpty(requestJson)) {
// Gson gson = new Gson();
// // 定义 Map 的类型
// Type type = new TypeToken<Map<String, String>>() {}.getType();
// // 将 JSON 字符串转换为 Map
// parameters = gson.fromJson(requestJson, type);
// path += "?";
// path += mapToQueryString(parameters);
// httpSampler.setPath(path); // 提取路径
// }
return httpSampler;
}
@@ -249,11 +258,12 @@ public class JMeterUtil {
* 创建post请求方式
* @param urlString
* @param port
* @param requestJson
* @param requestBody
* @param requestParams
* @return
* @throws MalformedURLException
*/
private static HTTPSamplerProxy createPostHttpSampler(String urlString, int port, String requestJson) throws MalformedURLException {
private static HTTPSamplerProxy createPostHttpSampler(String urlString, int port, String requestBody, String requestParams) throws MalformedURLException {
URL url = new URL(urlString);
// 提取域名(不包括端口号)
String domain = url.getHost();
@@ -265,15 +275,18 @@ public class JMeterUtil {
httpSampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
httpSampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
httpSampler.setDomain(domain);
if (!StringUtils.isEmpty(requestParams)) {
path = path + "?" + requestParams;
}
httpSampler.setPath(path);
httpSampler.setPort(port);
httpSampler.setMethod("POST");
httpSampler.setConnectTimeout("5000");
httpSampler.setUseKeepAlive(true);
// 设置请求头为 JSON
// 设置请求
httpSampler.setPostBodyRaw(true); // 使用原始请求体
httpSampler.addNonEncodedArgument("", requestJson, "");
httpSampler.addNonEncodedArgument("", requestBody, "");
return httpSampler;
}
@@ -398,12 +411,21 @@ public class JMeterUtil {
Map<String, String> resultMap = new HashMap<>();
Element httpSampleElement = (Element) httpSampleNode;
String costMiliseconds = httpSampleElement.getAttribute("t");
String responseCode = httpSampleElement.getAttribute("rc");
resultMap.put("responseCode", responseCode);
resultMap.put("costMiliseconds", costMiliseconds);
// 提取子节点<responseData>的内容
NodeList responseDataList = httpSampleElement.getElementsByTagName("responseData");
if (responseDataList.getLength() > 0) {
Element responseDataElement = (Element) responseDataList.item(0);
resultMap.put("costMiliseconds", responseDataElement.getTextContent());
resultMap.put("responseBody", responseDataElement.getTextContent());
return resultMap;
}
// 提取子节点<responseHeader>的内容
NodeList responseHeaderList = httpSampleElement.getElementsByTagName("responseHeader");
if (responseHeaderList.getLength() > 0) {
Element responseHeaderElement = (Element) responseHeaderList.item(0);
resultMap.put("responseHeader", responseHeaderElement.getTextContent());
return resultMap;
}
}
@@ -413,13 +435,56 @@ public class JMeterUtil {
return null;
}
/**
* 从响应头中读取Map信息结构
* @param responseHeader
* @return
*/
public static Map<String, String> parseHeaders(String responseHeader) {
Map<String, String> headerMap = new HashMap<>();
// 按行拆分
String[] lines = responseHeader.split("\n");
// 遍历每一行
for (String line : lines) {
// 忽略空行和 HTTP 状态行
if (line.trim().isEmpty() || line.startsWith("HTTP/")) {
continue;
}
// 按冒号拆分键值对
int colonIndex = line.indexOf(":");
if (colonIndex > 0) {
String key = line.substring(0, colonIndex).trim();
String value = line.substring(colonIndex + 1).trim();
headerMap.put(key, value);
}
}
return headerMap;
}
/**
* 根据 JSONPath 表达式从 JSON 中提取字段值
*
* @param json JSON 字符串
* @param expression JSONPath 表达式
* @return 字段值,如果字段不存在则返回 null
*/
public static String extractFieldValue(String json, String expression) {
try {
Object result = JsonPath.read(json, expression);
return result != null ? result.toString() : null;
} catch (PathNotFoundException e) {
// 如果字段不存在,返回 null
return null;
}
}
public static void main(String[] args) {
String paramJson = "{\"md5Value\":\"value1\",\"fileName\":\"value2\"}";
paramJson = "{\"name\":\"John\",\"city\":\"New York\",\"age\":30}";
String requestHeader = "{\"Content-Type\":\"application/json; charset=UTF-8\",\"Authorization\":\"Bearer token123\"}";
String jmeterHomePath = "D:/apache-jmeter-5.4.3";
// String result = getJmeterResult("http://127.0.0.1:3000/api/items/add", 3000, "POST", paramJson, requestHeader, jmeterHomePath);
getJmeterResult(123L, "http://127.0.0.1:3000/api/items/user", 3000, "GET", paramJson, requestHeader, jmeterHomePath);
// getJmeterResult(123L, "http://127.0.0.1:3000/api/items/user", 3000, "GET", paramJson, requestHeader, jmeterHomePath);
// System.out.println(result);
}
}

View File

@@ -39,6 +39,8 @@ public class TestCaseResult extends BaseEntity {
/** http 响应体 */
@Excel(name = "http 响应体")
private String responseBody;
/** sql结果 */
private String sqlResult;
/** 循环次 */

View File

@@ -0,0 +1,28 @@
package com.test.test.domain.qo;
import lombok.Data;
/**
* @author liangdaliang
* @Description校验规则
* @date 2025-02-19 17:33
*/
@Data
public class AssertRule {
/**
* 描述
*/
private String name;
/**
* 对象
*/
private String source;
/**
* 条件
*/
private String fn;
/**
* 比较值
*/
private String target;
}

View File

@@ -0,0 +1,21 @@
package com.test.test.domain.qo;
import lombok.Data;
/**
* @author liangdaliang
* @Description
* @date 2025-02-19 21:02
*/
@Data
public class AssertRuleResult extends AssertRule {
/**
* 实际值
*/
private String value;
/**
* 结果:通过;未通过
*/
private String result;
}

View File

@@ -0,0 +1,28 @@
package com.test.test.domain.qo;
import lombok.Data;
/**
* @author liangdaliang
* @Description提取规则
* @date 2025-02-19 16:04
*/
@Data
public class ExtractionRule {
/**
* 变量名
*/
private String name;
/**
* 提取方式
*/
private String type;
/**
* 提取对象
*/
private String content;
/**
* 提取表达式
*/
private String path;
}

View File

@@ -0,0 +1,16 @@
package com.test.test.domain.qo;
import lombok.Data;
/**
* @author liangdaliang
* @Description提取规则结果
* @date 2025-02-19 16:12
*/
@Data
public class ExtractionRuleResult extends ExtractionRule {
/**
* 提取结果
*/
private String value;
}

View File

@@ -1,8 +1,9 @@
package com.test.test.mapper;
import java.util.List;
import com.test.test.domain.TestCaseStep;
import java.util.List;
/**
* 用例步骤Mapper接口
*
@@ -58,4 +59,12 @@ public interface TestCaseStepMapper
* @return 结果
*/
public int deleteTestCaseStepByIds(Long[] ids);
/**
* 根据用例id查询用例步骤列表并按照步骤顺序排序
*
* @param caseId 用例id
* @return 用例步骤集合
*/
public List<TestCaseStep> selectTestCaseStepListByCaseId(Long caseId);
}

View File

@@ -0,0 +1,62 @@
package com.test.test.service;
import com.test.test.domain.TestCaseLog;
import java.util.List;
/**
* 用例日志Service接口
*
* @author liangdl
* @date 2025-02-18
*/
public interface ITestCaseLogService
{
/**
* 查询用例日志
*
* @param id 用例日志主键
* @return 用例日志
*/
public TestCaseLog selectTestCaseLogById(Long id);
/**
* 查询用例日志列表
*
* @param testCaseLog 用例日志
* @return 用例日志集合
*/
public List<TestCaseLog> selectTestCaseLogList(TestCaseLog testCaseLog);
/**
* 新增用例日志
*
* @param testCaseLog 用例日志
* @return 结果
*/
public int insertTestCaseLog(TestCaseLog testCaseLog);
/**
* 修改用例日志
*
* @param testCaseLog 用例日志
* @return 结果
*/
public int updateTestCaseLog(TestCaseLog testCaseLog);
/**
* 批量删除用例日志
*
* @param ids 需要删除的用例日志主键集合
* @return 结果
*/
public int deleteTestCaseLogByIds(Long[] ids);
/**
* 删除用例日志信息
*
* @param id 用例日志主键
* @return 结果
*/
public int deleteTestCaseLogById(Long id);
}

View File

@@ -0,0 +1,62 @@
package com.test.test.service;
import com.test.test.domain.TestCaseResult;
import java.util.List;
/**
* 用例执行报告Service接口
*
* @author liangdl
* @date 2025-02-18
*/
public interface ITestCaseResultService
{
/**
* 查询用例执行报告
*
* @param id 用例执行报告主键
* @return 用例执行报告
*/
public TestCaseResult selectTestCaseResultById(Long id);
/**
* 查询用例执行报告列表
*
* @param testCaseResult 用例执行报告
* @return 用例执行报告集合
*/
public List<TestCaseResult> selectTestCaseResultList(TestCaseResult testCaseResult);
/**
* 新增用例执行报告
*
* @param testCaseResult 用例执行报告
* @return 结果
*/
public int insertTestCaseResult(TestCaseResult testCaseResult);
/**
* 修改用例执行报告
*
* @param testCaseResult 用例执行报告
* @return 结果
*/
public int updateTestCaseResult(TestCaseResult testCaseResult);
/**
* 批量删除用例执行报告
*
* @param ids 需要删除的用例执行报告主键集合
* @return 结果
*/
public int deleteTestCaseResultByIds(Long[] ids);
/**
* 删除用例执行报告信息
*
* @param id 用例执行报告主键
* @return 结果
*/
public int deleteTestCaseResultById(Long id);
}

View File

@@ -0,0 +1,71 @@
package com.test.test.service;
import com.test.test.domain.TestCase;
import java.util.List;
/**
* 用例Service接口
*
* @author liangdl
* @date 2025-02-18
*/
public interface ITestCaseService
{
/**
* 查询用例
*
* @param id 用例主键
* @return 用例
*/
public TestCase selectTestCaseById(Long id);
/**
* 查询用例列表
*
* @param testCase 用例
* @return 用例集合
*/
public List<TestCase> selectTestCaseList(TestCase testCase);
/**
* 新增用例
*
* @param testCase 用例
* @return 结果
*/
public int insertTestCase(TestCase testCase);
/**
* 修改用例
*
* @param testCase 用例
* @return 结果
*/
public int updateTestCase(TestCase testCase);
/**
* 批量删除用例
*
* @param ids 需要删除的用例主键集合
* @return 结果
*/
public int deleteTestCaseByIds(Long[] ids);
/**
* 删除用例信息
*
* @param id 用例主键
* @return 结果
*/
public int deleteTestCaseById(Long id);
/**
* 执行用例计划
*
* @param id 用例主键id
* @param jmeterHomePath jmeter安装路径
* @return 是否成功
*/
public boolean executeTestCaseById(Long id, String jmeterHomePath);
}

View File

@@ -61,6 +61,14 @@ public interface ITestCaseStepService
*/
public int deleteTestCaseStepById(Long id);
/**
* 根据用例id查询用例步骤列表并按照步骤顺序排序
*
* @param caseId 用例id
* @return 用例步骤集合
*/
public List<TestCaseStep> selectTestCaseStepListByCaseId(Long caseId);
/**
* 执行jmeter用例步骤计划
*

View File

@@ -0,0 +1,96 @@
package com.test.test.service.impl;
import com.test.test.domain.TestCaseLog;
import com.test.test.mapper.TestCaseLogMapper;
import com.test.test.service.ITestCaseLogService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 用例日志Service业务层处理
*
* @author liangdl
* @date 2025-02-18
*/
@Slf4j
@Service
public class TestCaseLogServiceImpl implements ITestCaseLogService
{
@Resource
private TestCaseLogMapper testCaseLogMapper;
/**
* 查询用例日志
*
* @param id 用例日志主键
* @return 用例日志
*/
@Override
public TestCaseLog selectTestCaseLogById(Long id)
{
return testCaseLogMapper.selectTestCaseLogById(id);
}
/**
* 查询用例日志列表
*
* @param testCaseLog 用例日志
* @return 用例日志
*/
@Override
public List<TestCaseLog> selectTestCaseLogList(TestCaseLog testCaseLog)
{
return testCaseLogMapper.selectTestCaseLogList(testCaseLog);
}
/**
* 新增用例日志
*
* @param testCaseLog 用例日志
* @return 结果
*/
@Override
public int insertTestCaseLog(TestCaseLog testCaseLog)
{
return testCaseLogMapper.insertTestCaseLog(testCaseLog);
}
/**
* 修改用例日志
*
* @param testCaseLog 用例日志
* @return 结果
*/
@Override
public int updateTestCaseLog(TestCaseLog testCaseLog)
{
return testCaseLogMapper.updateTestCaseLog(testCaseLog);
}
/**
* 批量删除用例日志
*
* @param ids 需要删除的用例日志主键
* @return 结果
*/
@Override
public int deleteTestCaseLogByIds(Long[] ids)
{
return testCaseLogMapper.deleteTestCaseLogByIds(ids);
}
/**
* 删除用例日志信息
*
* @param id 用例日志主键
* @return 结果
*/
@Override
public int deleteTestCaseLogById(Long id)
{
return testCaseLogMapper.deleteTestCaseLogById(id);
}
}

View File

@@ -0,0 +1,96 @@
package com.test.test.service.impl;
import com.test.test.domain.TestCaseResult;
import com.test.test.mapper.TestCaseResultMapper;
import com.test.test.service.ITestCaseResultService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 用例执行报告Service业务层处理
*
* @author liangdl
* @date 2025-02-18
*/
@Slf4j
@Service
public class TestCaseResultServiceImpl implements ITestCaseResultService
{
@Resource
private TestCaseResultMapper testCaseResultMapper;
/**
* 查询用例执行报告
*
* @param id 用例执行报告主键
* @return 用例执行报告
*/
@Override
public TestCaseResult selectTestCaseResultById(Long id)
{
return testCaseResultMapper.selectTestCaseResultById(id);
}
/**
* 查询用例执行报告列表
*
* @param testCaseResult 用例执行报告
* @return 用例执行报告
*/
@Override
public List<TestCaseResult> selectTestCaseResultList(TestCaseResult testCaseResult)
{
return testCaseResultMapper.selectTestCaseResultList(testCaseResult);
}
/**
* 新增用例执行报告
*
* @param testCaseResult 用例执行报告
* @return 结果
*/
@Override
public int insertTestCaseResult(TestCaseResult testCaseResult)
{
return testCaseResultMapper.insertTestCaseResult(testCaseResult);
}
/**
* 修改用例执行报告
*
* @param testCaseResult 用例执行报告
* @return 结果
*/
@Override
public int updateTestCaseResult(TestCaseResult testCaseResult)
{
return testCaseResultMapper.updateTestCaseResult(testCaseResult);
}
/**
* 批量删除用例执行报告
*
* @param ids 需要删除的用例执行报告主键
* @return 结果
*/
@Override
public int deleteTestCaseResultByIds(Long[] ids)
{
return testCaseResultMapper.deleteTestCaseResultByIds(ids);
}
/**
* 删除用例执行报告信息
*
* @param id 用例执行报告主键
* @return 结果
*/
@Override
public int deleteTestCaseResultById(Long id)
{
return testCaseResultMapper.deleteTestCaseResultById(id);
}
}

View File

@@ -0,0 +1,460 @@
package com.test.test.service.impl;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.test.common.utils.DateUtils;
import com.test.common.utils.JMeterUtil;
import com.test.common.utils.StringUtils;
import com.test.test.domain.TestCase;
import com.test.test.domain.TestCaseResult;
import com.test.test.domain.TestCaseStep;
import com.test.test.domain.qo.AssertRule;
import com.test.test.domain.qo.AssertRuleResult;
import com.test.test.domain.qo.ExtractionRule;
import com.test.test.domain.qo.ExtractionRuleResult;
import com.test.test.mapper.TestCaseMapper;
import com.test.test.mapper.TestCaseResultMapper;
import com.test.test.service.ITestCaseService;
import com.test.test.service.ITestCaseStepService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 用例Service业务层处理
*
* @author liangdl
* @date 2025-02-18
*/
@Slf4j
@Service
public class TestCaseServiceImpl implements ITestCaseService
{
@Resource
private TestCaseMapper testCaseMapper;
@Resource
private TestCaseResultMapper testCaseResultMapper;
@Autowired
private ITestCaseStepService testCaseStepService;
/**
* 查询用例
*
* @param id 用例主键
* @return 用例
*/
@Override
public TestCase selectTestCaseById(Long id)
{
return testCaseMapper.selectTestCaseById(id);
}
/**
* 查询用例列表
*
* @param testCase 用例
* @return 用例
*/
@Override
public List<TestCase> selectTestCaseList(TestCase testCase)
{
return testCaseMapper.selectTestCaseList(testCase);
}
/**
* 新增用例
*
* @param testCase 用例
* @return 结果
*/
@Override
public int insertTestCase(TestCase testCase)
{
testCase.setCreateTime(DateUtils.getNowDate());
return testCaseMapper.insertTestCase(testCase);
}
/**
* 修改用例
*
* @param testCase 用例
* @return 结果
*/
@Override
public int updateTestCase(TestCase testCase)
{
testCase.setUpdateTime(DateUtils.getNowDate());
return testCaseMapper.updateTestCase(testCase);
}
/**
* 批量删除用例
*
* @param ids 需要删除的用例主键
* @return 结果
*/
@Override
public int deleteTestCaseByIds(Long[] ids)
{
return testCaseMapper.deleteTestCaseByIds(ids);
}
/**
* 删除用例信息
*
* @param id 用例主键
* @return 结果
*/
@Override
public int deleteTestCaseById(Long id)
{
return testCaseMapper.deleteTestCaseById(id);
}
/**
* 执行用例计划
*
* @param id 用例主键id
* @param jmeterHomePath jmeter安装路径
* @return 是否成功
*/
@Override
public boolean executeTestCaseById(Long id, String jmeterHomePath) {
TestCase testCase = this.selectTestCaseById(id);
if (testCase == null || "2".equals(testCase.getDelFlag())) {
log.error("用例计划已被删除,不能执行!");
return false;
}
List<TestCaseStep> testCaseStepList = testCaseStepService.selectTestCaseStepListByCaseId(id);
for (TestCaseStep testCaseStep : testCaseStepList) {
if (testCaseStep.getType() == 1L) {
// http接口处理
boolean httpTestResult = doHttpRequestTest(testCase, testCaseStep, jmeterHomePath);
if (!httpTestResult) {
log.error("用例步骤:{}执行失败!", testCaseStep.getName());
return false;
}
} else if (testCaseStep.getType() == 2L) {
// 数据库接口处理
} else if (testCaseStep.getType() == 3L) {
// 循环节点处理
boolean pollTestResult = doPollRequestTest(testCase, testCaseStep, jmeterHomePath);
if (!pollTestResult) {
log.error("循环用例步骤:{}执行失败!", testCaseStep.getName());
return false;
}
} else if (testCaseStep.getType() == 4L) {
// 轮询节点处理
boolean loopTestResult = doLoopRequestTest(testCase, testCaseStep, jmeterHomePath);
if (!loopTestResult) {
log.error("轮询用例步骤:{}执行失败!", testCaseStep.getName());
return false;
}
} else {
log.error("错误的用例步骤类型!");
}
}
return true;
}
/**
* 处理http接口测试
* @param testCase
* @param testCaseStep
* @param jmeterHomePath
* @return 成功或失败
*/
private boolean doHttpRequestTest(TestCase testCase, TestCaseStep testCaseStep, String jmeterHomePath) {
try {
String assignment = testCaseStep.getAssignment(); // 参数提取
String assertion = testCaseStep.getAssertion(); // 校验规则
TestCaseResult testCaseResult = new TestCaseResult();
testCaseResult.setExecuteTime(DateUtils.getNowDate());
Map<String, String> resultMap = testCaseStepService.executeJmeterTestCaseStepById(testCaseStep.getId(), jmeterHomePath);
testCaseResult.setCaseId(testCase.getId());
testCaseResult.setStepId(testCaseStep.getId());
if (resultMap != null) {
testCaseResult.setResponseHeader(resultMap.get("responseHeader"));
testCaseResult.setResponseBody(resultMap.get("responseBody"));
// 处理参数提取
Map<String, String> assignmentResultMap = new HashMap<>();
String assignmentResult = this.dealTestCaseStepAssignment(resultMap, assignmentResultMap, assignment);
testCaseResult.setAssignment(assignmentResult);
// 根据提取结果处理校验规则
String assertionResult = this.dealTestCaseStepAssertion(assignmentResultMap, assertion);
testCaseResult.setAssertion(assertionResult);
Long useTime = null;
if (resultMap.get("useTime") != null) {
useTime = Long.valueOf(resultMap.get("useTime"));
}
testCaseResult.setUseTime(useTime);
if ("fail".equals(assignmentResultMap.get("assertionResult"))) {
testCaseResult.setStatus("失败");
testCaseResultMapper.insertTestCaseResult(testCaseResult);
return false;
} else {
testCaseResult.setStatus("成功");
testCaseResultMapper.insertTestCaseResult(testCaseResult);
}
} else {
testCaseResult.setAssignment(assignment);
testCaseResult.setAssertion(assertion);
testCaseResult.setUseTime(0L);
testCaseResult.setStatus("失败");
testCaseResultMapper.insertTestCaseResult(testCaseResult);
return false;
}
} catch (Exception e) {
log.error("HTTP请求测试发生异常: ", e);
return false;
}
return true;
}
/**
* 处理循环节点接口测试
* @param testCase
* @param testCaseStep
* @param jmeterHomePath
* @return 是否成功
*/
private boolean doPollRequestTest(TestCase testCase, TestCaseStep testCaseStep, String jmeterHomePath) {
try {
// 先查出所有子节点测试步骤
long pollCountCount = testCaseStep.getCount();
Integer async = testCaseStep.getAsync();
TestCaseResult testCaseResult = new TestCaseResult();
testCaseResult.setExecuteTime(DateUtils.getNowDate());
testCaseResult.setCaseId(testCase.getId());
testCaseResult.setStepId(testCaseStep.getId());
Long parentId = testCaseStep.getId();
TestCaseStep testCaseStepInput = new TestCaseStep();
testCaseStepInput.setCaseId(testCase.getId());
testCaseStepInput.setParentId(parentId);
testCaseStepInput.setDelFlag("0");
List<TestCaseStep> testCaseStepChildList = testCaseStepService.selectTestCaseStepList(testCaseStepInput);
long realPollCount = 1; // 实际循环次数
boolean pollResult = true;
long startTime = System.currentTimeMillis();
for (int i = 0; i < pollCountCount; i++) {
for (TestCaseStep testCaseStepChild : testCaseStepChildList) {
if (testCaseStepChild.getType() == 1L) {
// http接口处理
boolean httpTestResult = doHttpRequestTest(testCase, testCaseStepChild, jmeterHomePath);
if (!httpTestResult) {
log.error("子用例步骤:{}执行失败!", testCaseStepChild.getName());
pollResult = false;
break;
}
} else if (testCaseStepChild.getType() == 2L) {
// 数据库接口处理
}
}
if (!pollResult) {
break;
}
realPollCount++;
}
testCaseResult.setUseTime(System.currentTimeMillis() - startTime);
if (pollResult) {
testCaseResult.setStatus("成功");
testCaseResult.setPollingCount(realPollCount);
testCaseResultMapper.insertTestCaseResult(testCaseResult);
return true;
} else {
testCaseResult.setStatus("失败");
testCaseResult.setPollingCount(realPollCount);
testCaseResultMapper.insertTestCaseResult(testCaseResult);
return false;
}
} catch (Exception e) {
log.error("循环节点测试发生异常: ", e);
return false;
}
}
/**
* 处理轮询节点接口测试
* @param testCase
* @param testCaseStep
* @param jmeterHomePath
* @return 是否成功
*/
private boolean doLoopRequestTest(TestCase testCase, TestCaseStep testCaseStep, String jmeterHomePath) {
try {
// 先查出所有子节点测试步骤
String breakError = testCaseStep.getBreakError();
long interval = testCaseStep.getInterval() == null ? 0 : testCaseStep.getInterval();;
long loopCountCount = testCaseStep.getCount();
TestCaseResult testCaseResult = new TestCaseResult();
testCaseResult.setExecuteTime(DateUtils.getNowDate());
testCaseResult.setCaseId(testCase.getId());
testCaseResult.setStepId(testCaseStep.getId());
Long parentId = testCaseStep.getId();
TestCaseStep testCaseStepInput = new TestCaseStep();
testCaseStepInput.setCaseId(testCase.getId());
testCaseStepInput.setParentId(parentId);
testCaseStepInput.setDelFlag("0");
List<TestCaseStep> testCaseStepChildList = testCaseStepService.selectTestCaseStepList(testCaseStepInput);
long realLoopCount = 1; // 实际轮询次数
boolean loopResult = false;
long startTime = System.currentTimeMillis();
int maxSize = testCaseStepChildList.size();
for (int i = 0; i < loopCountCount; i++) {
if (i > 0) {
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
log.error("线程睡眠被中断: ", e);
}
}
int index = 0;
for (TestCaseStep testCaseStepChild : testCaseStepChildList) {
if (testCaseStepChild.getType() == 1L) {
// http接口处理
boolean httpTestResult = doHttpRequestTest(testCase, testCaseStepChild, jmeterHomePath);
if (!httpTestResult) {
log.error("子用例步骤:{}执行失败!", testCaseStepChild.getName());
break;
}
} else if (testCaseStepChild.getType() == 2L) {
// 数据库接口处理
}
index ++;
}
realLoopCount ++;
if (maxSize == index) {
loopResult = true;
break;
}
}
testCaseResult.setUseTime(System.currentTimeMillis() - startTime);
if (loopResult) {
testCaseResult.setStatus("成功");
testCaseResult.setLoopCount(realLoopCount);
testCaseResultMapper.insertTestCaseResult(testCaseResult);
return true;
} else {
testCaseResult.setStatus("失败");
testCaseResult.setLoopCount(realLoopCount);
testCaseResultMapper.insertTestCaseResult(testCaseResult);
return false;
}
} catch (Exception e) {
log.error("轮询节点测试发生异常: ", e);
return false;
}
}
/**
* 处理响应字段提取
* @param resultMap
* @param assignmentResultMap
* @param assignment
* @return 处理后的提取结果
*/
private String dealTestCaseStepAssignment(Map<String, String> resultMap, Map<String, String> assignmentResultMap, String assignment) {
String responseHeader = resultMap.get("responseHeader");
String responseBody = resultMap.get("responseBody");
String responseCode = resultMap.get("responseCode");
if (!StringUtils.isEmpty(assignment) && !"[]".equals(assignment)) {
Map<String, String> responseHeaderMap = JMeterUtil.parseHeaders(responseHeader);
Gson gson = new Gson();
Type ruleListType = new TypeToken<List<ExtractionRule>>() {}.getType();
// 将 JSON 字符串解析为 List<ExtractionRule>
List<ExtractionRule> rules = gson.fromJson(assignment, ruleListType);
List<ExtractionRuleResult> ruleResultList = new ArrayList<>();
for (ExtractionRule rule : rules) {
ExtractionRuleResult ruleResult = new ExtractionRuleResult();
BeanUtils.copyProperties(rule, ruleResult);
String type = rule.getType();
String content = rule.getContent();
String path = rule.getPath();
if ("${RESPONSE_BODY}".equals(content)) {
if (type.startsWith("JSON")) {
if (!path.startsWith("$.")) {
path = "$." + path;
}
String value = JMeterUtil.extractFieldValue(responseBody, path);
ruleResult.setValue(value);
}
} else if ("${RESPONSE_HEADER}".equals(content)) {
String value = responseHeaderMap.get(path);
ruleResult.setValue(value);
} else if ("${RESPONSE_CODE}".equals(content)) {
ruleResult.setValue(responseCode);
}
assignmentResultMap.put(rule.getName(), ruleResult.getValue());
ruleResultList.add(ruleResult);
}
return gson.toJson(ruleResultList);
} else {
return assignment;
}
}
/**
* 校验测试用例步骤是否通过
* @param assignmentResultMap
* @param assertion
* @return
*/
private String dealTestCaseStepAssertion(Map<String, String> assignmentResultMap, String assertion) {
if (!StringUtils.isEmpty(assertion) && !"[]".equals(assertion)) {
Gson gson = new Gson();
Type ruleListType = new TypeToken<List<AssertRule>>() {}.getType();
// 将 JSON 字符串解析为 List<AssertRule>
List<AssertRule> rules = gson.fromJson(assertion, ruleListType);
List<AssertRuleResult> ruleResultList = new ArrayList<>();
for (AssertRule rule : rules) {
AssertRuleResult ruleResult = new AssertRuleResult();
BeanUtils.copyProperties(rule, ruleResult);
String source = rule.getSource();
String target = rule.getTarget();
String fn = rule.getFn();
String value = assignmentResultMap.get(source);
ruleResult.setValue(value);
if ("等于".equals(fn)) {
if (target.equals(value)) {
ruleResult.setResult("通过");
} else {
ruleResult.setResult("未通过");
}
} else if ("大于".equals(fn)) {
int result = value.compareTo(target);
if (result > 0) {
ruleResult.setResult("通过");
} else {
ruleResult.setResult("未通过");
}
} else if ("小于".equals(fn)) {
int result = value.compareTo(target);
if (result < 0) {
ruleResult.setResult("通过");
} else {
ruleResult.setResult("未通过");
}
} else {
ruleResult.setResult("未通过");
}
if ("未通过".equals(ruleResult.getResult())) {
assignmentResultMap.put("assertionResult", "fail");
}
ruleResultList.add(ruleResult);
}
return gson.toJson(ruleResultList);
} else {
return assertion;
}
}
}

View File

@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.test.test.mapper.TestCaseResultMapper">
<resultMap type="TestCaseResult" id="TestCaseResultResult">
<result property="id" column="id" />
<result property="caseId" column="case_id" />
<result property="stepId" column="step_id" />
<result property="responseHeader" column="response_header" />
<result property="responseBody" column="response_body" />
<result property="sqlResult" column="sql_result" />
<result property="pollingCount" column="polling_count" />
<result property="loopCount" column="loop_count" />
<result property="assignment" column="assignment" />
<result property="assertion" column="assertion" />
<result property="useTime" column="use_time" />
<result property="executeTime" column="execute_time" />
<result property="status" column="status" />
</resultMap>
<sql id="selectTestCaseResultVo">
select id, case_id, step_id, response_header, response_body, sql_result, polling_count, loop_count, assignment, assertion, use_time, execute_time, status from test_case_result
</sql>
<select id="selectTestCaseResultList" parameterType="TestCaseResult" resultMap="TestCaseResultResult">
<include refid="selectTestCaseResultVo"/>
<where>
<if test="caseId != null "> and case_id = #{caseId}</if>
<if test="stepId != null "> and step_id = #{stepId}</if>
<if test="responseHeader != null and responseHeader != ''"> and response_header = #{responseHeader}</if>
<if test="responseBody != null and responseBody != ''"> and response_body = #{responseBody}</if>
<if test="sqlResult != null and sqlResult != ''"> and sql_result = #{sqlResult}</if>
<if test="pollingCount != null "> and polling_count = #{pollingCount}</if>
<if test="loopCount != null "> and loop_count = #{loopCount}</if>
<if test="assignment != null and assignment != ''"> and assignment = #{assignment}</if>
<if test="assertion != null and assertion != ''"> and assertion = #{assertion}</if>
<if test="useTime != null "> and use_time = #{useTime}</if>
<if test="executeTime != null "> and execute_time = #{executeTime}</if>
<if test="status != null and status != ''"> and status = #{status}</if>
</where>
</select>
<select id="selectTestCaseResultById" parameterType="Long" resultMap="TestCaseResultResult">
<include refid="selectTestCaseResultVo"/>
where id = #{id}
</select>
<insert id="insertTestCaseResult" parameterType="TestCaseResult" useGeneratedKeys="true" keyProperty="id">
insert into test_case_result
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="caseId != null">case_id,</if>
<if test="stepId != null">step_id,</if>
<if test="responseHeader != null">response_header,</if>
<if test="responseBody != null">response_body,</if>
<if test="sqlResult != null">sql_result,</if>
<if test="pollingCount != null">polling_count,</if>
<if test="loopCount != null">loop_count,</if>
<if test="assignment != null">assignment,</if>
<if test="assertion != null">assertion,</if>
<if test="useTime != null">use_time,</if>
<if test="executeTime != null">execute_time,</if>
<if test="status != null">status,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="caseId != null">#{caseId},</if>
<if test="stepId != null">#{stepId},</if>
<if test="responseHeader != null">#{responseHeader},</if>
<if test="responseBody != null">#{responseBody},</if>
<if test="sqlResult != null">#{sqlResult},</if>
<if test="pollingCount != null">#{pollingCount},</if>
<if test="loopCount != null">#{loopCount},</if>
<if test="assignment != null">#{assignment},</if>
<if test="assertion != null">#{assertion},</if>
<if test="useTime != null">#{useTime},</if>
<if test="executeTime != null">#{executeTime},</if>
<if test="status != null">#{status},</if>
</trim>
</insert>
<update id="updateTestCaseResult" parameterType="TestCaseResult">
update test_case_result
<trim prefix="SET" suffixOverrides=",">
<if test="caseId != null">case_id = #{caseId},</if>
<if test="stepId != null">step_id = #{stepId},</if>
<if test="responseHeader != null">response_header = #{responseHeader},</if>
<if test="responseBody != null">response_body = #{responseBody},</if>
<if test="sqlResult != null">sql_result = #{sqlResult},</if>
<if test="pollingCount != null">polling_count = #{pollingCount},</if>
<if test="loopCount != null">loop_count = #{loopCount},</if>
<if test="assignment != null">assignment = #{assignment},</if>
<if test="assertion != null">assertion = #{assertion},</if>
<if test="useTime != null">use_time = #{useTime},</if>
<if test="executeTime != null">execute_time = #{executeTime},</if>
<if test="status != null">status = #{status},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteTestCaseResultById" parameterType="Long">
delete from test_case_result where id = #{id}
</delete>
<delete id="deleteTestCaseResultByIds" parameterType="String">
delete from test_case_result where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

View File

@@ -67,6 +67,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="assignment != null and assignment != ''"> and assignment = #{assignment}</if>
<if test="assertion != null and assertion != ''"> and assertion = #{assertion}</if>
</where>
ORDER BY step_num
</select>
<select id="selectTestCaseStepById" parameterType="Long" resultMap="TestCaseStepResult">
@@ -183,4 +184,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{id}
</foreach>
</delete>
<select id="selectTestCaseStepListByCaseId" parameterType="Long" resultMap="TestCaseStepResult">
<include refid="selectTestCaseStepVo"/>
where case_id = #{caseId} and del_flag = '0' and parent_id is null
ORDER BY step_num
</select>
</mapper>