refactor(测试计划): 优化计划列表统计
This commit is contained in:
parent
b29118595d
commit
bad708148a
|
@ -77,28 +77,6 @@ CREATE INDEX idx_pos ON test_plan_api_scenario(pos);
|
||||||
ALTER TABLE test_plan_functional_case ADD COLUMN test_plan_collection_id VARCHAR(50) NOT NULL DEFAULT 'NONE' COMMENT '测试计划集id';
|
ALTER TABLE test_plan_functional_case ADD COLUMN test_plan_collection_id VARCHAR(50) NOT NULL DEFAULT 'NONE' COMMENT '测试计划集id';
|
||||||
CREATE INDEX idx_test_plan_collection_id ON test_plan_functional_case(test_plan_collection_id);
|
CREATE INDEX idx_test_plan_collection_id ON test_plan_functional_case(test_plan_collection_id);
|
||||||
|
|
||||||
-- 修改测试规划配置表
|
|
||||||
ALTER TABLE test_plan_allocation DROP `run_mode_config`;
|
|
||||||
ALTER TABLE test_plan_allocation ADD `test_resource_pool_id` VARCHAR(50) NOT NULL COMMENT '资源池ID';
|
|
||||||
ALTER TABLE test_plan_allocation ADD `retry_on_fail` BIT NOT NULL DEFAULT 0 COMMENT '是否失败重试' ;
|
|
||||||
ALTER TABLE test_plan_allocation ADD `retry_type` VARCHAR(50) NOT NULL COMMENT '失败重试类型(步骤/场景)' ;
|
|
||||||
ALTER TABLE test_plan_allocation ADD `retry_times` INT NOT NULL DEFAULT 1 COMMENT '失败重试次数' ;
|
|
||||||
ALTER TABLE test_plan_allocation ADD `retry_interval` INT NOT NULL DEFAULT 1000 COMMENT '失败重试间隔(单位: ms)' ;
|
|
||||||
ALTER TABLE test_plan_allocation ADD `stop_on_fail` BIT NOT NULL DEFAULT 0 COMMENT '是否失败停止' ;
|
|
||||||
CREATE INDEX idx_resource_pool_id ON test_plan_allocation(test_resource_pool_id);
|
|
||||||
|
|
||||||
-- 测试规划集类型
|
|
||||||
CREATE TABLE IF NOT EXISTS test_plan_allocation_type(
|
|
||||||
`id` VARCHAR(50) NOT NULL COMMENT 'ID' ,
|
|
||||||
`test_plan_id` VARCHAR(50) NOT NULL COMMENT '测试计划ID' ,
|
|
||||||
`name` VARCHAR(255) NOT NULL COMMENT '测试集类型名称' ,
|
|
||||||
`type` VARCHAR(50) NOT NULL COMMENT '测试集类型(功能/接口/场景)' ,
|
|
||||||
`execute_method` VARCHAR(50) NOT NULL COMMENT '执行方式(串行/并行)' ,
|
|
||||||
`pos` BIGINT NOT NULL COMMENT '自定义排序,间隔为2的N次幂' ,
|
|
||||||
PRIMARY KEY (id)
|
|
||||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '测试集类型';
|
|
||||||
CREATE INDEX idx_test_plan_id ON test_plan_allocation_type(test_plan_id);
|
|
||||||
|
|
||||||
-- 测试集
|
-- 测试集
|
||||||
CREATE TABLE IF NOT EXISTS test_plan_collection(
|
CREATE TABLE IF NOT EXISTS test_plan_collection(
|
||||||
`id` VARCHAR(50) NOT NULL COMMENT 'ID' ,
|
`id` VARCHAR(50) NOT NULL COMMENT 'ID' ,
|
||||||
|
|
|
@ -30,7 +30,7 @@ public class TestPlanStatisticsResponse {
|
||||||
private Double executeRate;
|
private Double executeRate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行进度中的用例数量统计 (暂定)
|
* 执行进度中的用例数量统计
|
||||||
*/
|
*/
|
||||||
@Schema(description = "成功用例数量")
|
@Schema(description = "成功用例数量")
|
||||||
private Integer successCount = 0;
|
private Integer successCount = 0;
|
||||||
|
@ -44,7 +44,7 @@ public class TestPlanStatisticsResponse {
|
||||||
private Integer pendingCount = 0;
|
private Integer pendingCount = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用例数中用例数量统计 (暂定)
|
* 用例数中用例数量统计
|
||||||
*/
|
*/
|
||||||
@Schema(description = "用例总数")
|
@Schema(description = "用例总数")
|
||||||
private Integer caseTotal = 0;
|
private Integer caseTotal = 0;
|
||||||
|
|
|
@ -57,4 +57,12 @@ public interface ExtTestPlanApiCaseMapper {
|
||||||
List<ModuleCountDTO> collectionCountByRequest(@Param("testPlanId") String testPlanId);
|
List<ModuleCountDTO> collectionCountByRequest(@Param("testPlanId") String testPlanId);
|
||||||
|
|
||||||
Long getMaxPosByCollectionId(String collectionId);
|
Long getMaxPosByCollectionId(String collectionId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取计划下的功能用例集合
|
||||||
|
*
|
||||||
|
* @param planIds 测试计划ID集合
|
||||||
|
* @return 计划功能用例集合
|
||||||
|
*/
|
||||||
|
List<TestPlanApiCase> getPlanApiCaseByIds(@Param("planIds") List<String> planIds);
|
||||||
}
|
}
|
||||||
|
|
|
@ -656,4 +656,18 @@
|
||||||
FROM test_plan_api_case
|
FROM test_plan_api_case
|
||||||
WHERE test_plan_collection_id = #{0}
|
WHERE test_plan_collection_id = #{0}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="getPlanApiCaseByIds" resultType="io.metersphere.plan.domain.TestPlanApiCase">
|
||||||
|
select tpac.test_plan_id testPlanId, tpac.api_case_id apiCaseId, tpac.last_exec_result lastExecResult
|
||||||
|
from test_plan_api_case tpac join api_test_case atc on atc.id = tpac.api_case_id
|
||||||
|
<where>
|
||||||
|
atc.deleted = false
|
||||||
|
<if test="planIds != null and planIds.size() > 0">
|
||||||
|
and tpac.test_plan_id in
|
||||||
|
<foreach collection="planIds" item="id" separator="," open="(" close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
|
@ -3,7 +3,6 @@ package io.metersphere.plan.mapper;
|
||||||
import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO;
|
import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO;
|
||||||
import io.metersphere.functional.dto.ProjectOptionDTO;
|
import io.metersphere.functional.dto.ProjectOptionDTO;
|
||||||
import io.metersphere.plan.domain.TestPlanApiScenario;
|
import io.metersphere.plan.domain.TestPlanApiScenario;
|
||||||
import io.metersphere.plan.dto.ApiCaseModuleDTO;
|
|
||||||
import io.metersphere.plan.dto.ApiScenarioModuleDTO;
|
import io.metersphere.plan.dto.ApiScenarioModuleDTO;
|
||||||
import io.metersphere.plan.dto.ResourceSelectParam;
|
import io.metersphere.plan.dto.ResourceSelectParam;
|
||||||
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
|
import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
|
||||||
|
@ -48,4 +47,12 @@ public interface ExtTestPlanApiScenarioMapper {
|
||||||
List<ProjectOptionDTO> selectRootIdByTestPlanId(@Param("testPlanId") String testPlanId);
|
List<ProjectOptionDTO> selectRootIdByTestPlanId(@Param("testPlanId") String testPlanId);
|
||||||
|
|
||||||
List<ApiScenarioModuleDTO> selectBaseByProjectIdAndTestPlanId(@Param("testPlanId") String testPlanId);
|
List<ApiScenarioModuleDTO> selectBaseByProjectIdAndTestPlanId(@Param("testPlanId") String testPlanId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取计划下的功能用例集合
|
||||||
|
*
|
||||||
|
* @param planIds 测试计划ID集合
|
||||||
|
* @return 计划功能用例集合
|
||||||
|
*/
|
||||||
|
List<TestPlanApiScenario> getPlanApiScenarioByIds(@Param("planIds") List<String> planIds);
|
||||||
}
|
}
|
||||||
|
|
|
@ -373,4 +373,17 @@
|
||||||
(SELECT api_scenario.module_id FROM api_scenario LEFT JOIN test_plan_api_scenario ON api_scenario.id = test_plan_api_scenario.api_scenario_id WHERE test_plan_api_scenario.test_plan_id = #{testPlanId} AND api_scenario.deleted = false)
|
(SELECT api_scenario.module_id FROM api_scenario LEFT JOIN test_plan_api_scenario ON api_scenario.id = test_plan_api_scenario.api_scenario_id WHERE test_plan_api_scenario.test_plan_id = #{testPlanId} AND api_scenario.deleted = false)
|
||||||
ORDER BY pos
|
ORDER BY pos
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="getPlanApiScenarioByIds" resultType="io.metersphere.plan.domain.TestPlanApiScenario">
|
||||||
|
select tpas.test_plan_id testPlanId, tpas.api_scenario_id apiScenarioId, tpas.last_exec_result lastExecResult
|
||||||
|
from test_plan_api_scenario tpas join api_scenario asce on asce.id = tpas.api_scenario_id
|
||||||
|
<where>
|
||||||
|
<if test="planIds != null and planIds.size() > 0">
|
||||||
|
tpas.test_plan_id in
|
||||||
|
<foreach collection="planIds" item="id" separator="," open="(" close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
|
@ -508,9 +508,7 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
||||||
public void initResourceDefaultCollection(String planId, List<TestPlanCollectionDTO> allCollections) {
|
public void initResourceDefaultCollection(String planId, List<TestPlanCollectionDTO> allCollections) {
|
||||||
// 批处理旧数据
|
// 批处理旧数据
|
||||||
List<TestPlanCollectionDTO> defaultCollections = new ArrayList<>();
|
List<TestPlanCollectionDTO> defaultCollections = new ArrayList<>();
|
||||||
allCollections.forEach(allCollection -> {
|
allCollections.forEach(allCollection -> defaultCollections.addAll(allCollection.getChildren()));
|
||||||
defaultCollections.addAll(allCollection.getChildren());
|
|
||||||
});
|
|
||||||
Map<String, TestPlanResourceService> beansOfType = applicationContext.getBeansOfType(TestPlanResourceService.class);
|
Map<String, TestPlanResourceService> beansOfType = applicationContext.getBeansOfType(TestPlanResourceService.class);
|
||||||
beansOfType.forEach((k, v) -> v.initResourceDefaultCollection(planId, defaultCollections));
|
beansOfType.forEach((k, v) -> v.initResourceDefaultCollection(planId, defaultCollections));
|
||||||
}
|
}
|
||||||
|
@ -860,7 +858,7 @@ public class TestPlanService extends TestPlanBaseUtilsService {
|
||||||
defaultCollection.setStopOnFail(false);
|
defaultCollection.setStopOnFail(false);
|
||||||
defaultCollection.setCreateUser(currentUser);
|
defaultCollection.setCreateUser(currentUser);
|
||||||
defaultCollection.setCreateTime(System.currentTimeMillis());
|
defaultCollection.setCreateTime(System.currentTimeMillis());
|
||||||
Long initPos = 1L;
|
long initPos = 1L;
|
||||||
for (CaseType caseType : CaseType.values()) {
|
for (CaseType caseType : CaseType.values()) {
|
||||||
// 测试集分类
|
// 测试集分类
|
||||||
TestPlanCollectionDTO parentCollectionDTO = new TestPlanCollectionDTO();
|
TestPlanCollectionDTO parentCollectionDTO = new TestPlanCollectionDTO();
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
package io.metersphere.plan.service;
|
package io.metersphere.plan.service;
|
||||||
|
|
||||||
import io.metersphere.plan.domain.TestPlanConfig;
|
import io.metersphere.plan.domain.*;
|
||||||
import io.metersphere.plan.domain.TestPlanConfigExample;
|
|
||||||
import io.metersphere.plan.domain.TestPlanFunctionalCase;
|
|
||||||
import io.metersphere.plan.dto.response.TestPlanBugPageResponse;
|
import io.metersphere.plan.dto.response.TestPlanBugPageResponse;
|
||||||
import io.metersphere.plan.dto.response.TestPlanStatisticsResponse;
|
import io.metersphere.plan.dto.response.TestPlanStatisticsResponse;
|
||||||
import io.metersphere.plan.mapper.ExtTestPlanBugMapper;
|
import io.metersphere.plan.mapper.*;
|
||||||
import io.metersphere.plan.mapper.ExtTestPlanFunctionalCaseMapper;
|
|
||||||
import io.metersphere.plan.mapper.TestPlanConfigMapper;
|
|
||||||
import io.metersphere.plan.utils.RateCalculateUtils;
|
import io.metersphere.plan.utils.RateCalculateUtils;
|
||||||
import io.metersphere.sdk.constants.ExecStatus;
|
import io.metersphere.sdk.constants.ExecStatus;
|
||||||
import io.metersphere.sdk.constants.ScheduleResourceType;
|
import io.metersphere.sdk.constants.ScheduleResourceType;
|
||||||
|
@ -35,52 +31,52 @@ public class TestPlanStatisticsService {
|
||||||
@Resource
|
@Resource
|
||||||
private ExtTestPlanFunctionalCaseMapper extTestPlanFunctionalCaseMapper;
|
private ExtTestPlanFunctionalCaseMapper extTestPlanFunctionalCaseMapper;
|
||||||
@Resource
|
@Resource
|
||||||
|
private ExtTestPlanApiCaseMapper extTestPlanApiCaseMapper;
|
||||||
|
@Resource
|
||||||
|
private ExtTestPlanApiScenarioMapper extTestPlanApiScenarioMapper;
|
||||||
|
@Resource
|
||||||
private ExtTestPlanBugMapper extTestPlanBugMapper;
|
private ExtTestPlanBugMapper extTestPlanBugMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private ScheduleMapper scheduleMapper;
|
private ScheduleMapper scheduleMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计划的用例统计数据
|
* 计划/计划组的用例统计数据
|
||||||
*
|
*
|
||||||
* @param plans 计划集合
|
* @param plans 计划集合
|
||||||
*/
|
*/
|
||||||
public void calculateCaseCount(List<? extends TestPlanStatisticsResponse> plans) {
|
public void calculateCaseCount(List<? extends TestPlanStatisticsResponse> plans) {
|
||||||
// TODO 计算计划下各种维度的用例统计数目 (待定)
|
|
||||||
/*
|
/*
|
||||||
* 1. 查询计划下的用例数据集合(目前只有功能用例)
|
* 1. 查询计划下的用例数据集合
|
||||||
* 2. 根据执行结果统计(结果小数保留两位)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
List<String> planIds = plans.stream().map(TestPlanStatisticsResponse::getId).toList();
|
List<String> planIds = plans.stream().map(TestPlanStatisticsResponse::getId).toList();
|
||||||
// 计划-功能用例的关联数据
|
Map<String, List<TestPlanFunctionalCase>> planFunctionalCaseMap = getFunctionalCaseMapByPlanIds(planIds);
|
||||||
List<TestPlanFunctionalCase> planFunctionalCases = extTestPlanFunctionalCaseMapper.getPlanFunctionalCaseByIds(planIds);
|
Map<String, List<TestPlanApiCase>> planApiCaseMap = getApiCaseMapByPlanIds(planIds);
|
||||||
Map<String, List<TestPlanFunctionalCase>> planFunctionalCaseMap = planFunctionalCases.stream().collect(Collectors.groupingBy(TestPlanFunctionalCase::getTestPlanId));
|
Map<String, List<TestPlanApiScenario>> planApiScenarioMap = getApiScenarioByPlanIds(planIds);
|
||||||
|
// 计划-缺陷的关联数据
|
||||||
List<TestPlanBugPageResponse> planBugs = extTestPlanBugMapper.countBugByIds(planIds);
|
List<TestPlanBugPageResponse> planBugs = extTestPlanBugMapper.countBugByIds(planIds);
|
||||||
Map<String, List<TestPlanBugPageResponse>> planBugMap = planBugs.stream().collect(Collectors.groupingBy(TestPlanBugPageResponse::getTestPlanId));
|
Map<String, List<TestPlanBugPageResponse>> planBugMap = planBugs.stream().collect(Collectors.groupingBy(TestPlanBugPageResponse::getTestPlanId));
|
||||||
// TODO: 计划-接口用例的关联数据
|
|
||||||
plans.forEach(plan -> {
|
plans.forEach(plan -> {
|
||||||
// 功能用例统计开始
|
|
||||||
List<TestPlanFunctionalCase> functionalCases = planFunctionalCaseMap.get(plan.getId());
|
List<TestPlanFunctionalCase> functionalCases = planFunctionalCaseMap.get(plan.getId());
|
||||||
plan.setFunctionalCaseCount(CollectionUtils.isNotEmpty(functionalCases) ? functionalCases.size() : 0);
|
plan.setFunctionalCaseCount(CollectionUtils.isNotEmpty(functionalCases) ? functionalCases.size() : 0);
|
||||||
|
List<TestPlanApiCase> apiCases = planApiCaseMap.get(plan.getId());
|
||||||
|
plan.setApiCaseCount(CollectionUtils.isNotEmpty(apiCases) ? apiCases.size() : 0);
|
||||||
|
List<TestPlanApiScenario> apiScenarios = planApiScenarioMap.get(plan.getId());
|
||||||
|
plan.setApiScenarioCount(CollectionUtils.isNotEmpty(apiScenarios) ? apiScenarios.size() : 0);
|
||||||
List<TestPlanBugPageResponse> bugs = planBugMap.get(plan.getId());
|
List<TestPlanBugPageResponse> bugs = planBugMap.get(plan.getId());
|
||||||
plan.setBugCount(CollectionUtils.isNotEmpty(bugs) ? bugs.size() : 0);
|
plan.setBugCount(CollectionUtils.isNotEmpty(bugs) ? bugs.size() : 0);
|
||||||
// TODO: 接口用例统计开始
|
plan.setCaseTotal(plan.getFunctionalCaseCount() + plan.getApiCaseCount() + plan.getApiScenarioCount());
|
||||||
|
|
||||||
// FIXME: CaseTotal后续会补充接口用例及场景的统计数据
|
|
||||||
plan.setCaseTotal(plan.getFunctionalCaseCount());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计划的{通过率, 执行进度}统计数据
|
* 计划/计划组的{通过率, 执行进度}统计数据
|
||||||
*
|
*
|
||||||
* @param planIds 计划ID集合
|
* @param planIds 计划ID集合
|
||||||
*/
|
*/
|
||||||
public List<TestPlanStatisticsResponse> calculateRate(List<String> planIds) {
|
public List<TestPlanStatisticsResponse> calculateRate(List<String> planIds) {
|
||||||
List<TestPlanStatisticsResponse> planStatisticsResponses = new ArrayList<>();
|
List<TestPlanStatisticsResponse> planStatisticsResponses = new ArrayList<>();
|
||||||
// TODO 计算计划下的用例通过率, 执行进度 (待定)
|
|
||||||
/*
|
/*
|
||||||
* 1. 查询计划下的用例数据集合(目前只有功能用例)
|
* 1. 查询计划下的用例数据集合
|
||||||
* 2. 根据执行结果统计(结果小数保留两位)
|
* 2. 根据执行结果统计(结果小数保留两位)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -89,9 +85,10 @@ public class TestPlanStatisticsService {
|
||||||
example.createCriteria().andTestPlanIdIn(planIds);
|
example.createCriteria().andTestPlanIdIn(planIds);
|
||||||
List<TestPlanConfig> testPlanConfigList = testPlanConfigMapper.selectByExample(example);
|
List<TestPlanConfig> testPlanConfigList = testPlanConfigMapper.selectByExample(example);
|
||||||
Map<String, TestPlanConfig> planConfigMap = testPlanConfigList.stream().collect(Collectors.toMap(TestPlanConfig::getTestPlanId, p -> p));
|
Map<String, TestPlanConfig> planConfigMap = testPlanConfigList.stream().collect(Collectors.toMap(TestPlanConfig::getTestPlanId, p -> p));
|
||||||
// 计划-功能用例的关联数据
|
// 关联的用例数据
|
||||||
List<TestPlanFunctionalCase> planFunctionalCases = extTestPlanFunctionalCaseMapper.getPlanFunctionalCaseByIds(planIds);
|
Map<String, List<TestPlanFunctionalCase>> planFunctionalCaseMap = getFunctionalCaseMapByPlanIds(planIds);
|
||||||
Map<String, List<TestPlanFunctionalCase>> planFunctionalCaseMap = planFunctionalCases.stream().collect(Collectors.groupingBy(TestPlanFunctionalCase::getTestPlanId));
|
Map<String, List<TestPlanApiCase>> planApiCaseMap = getApiCaseMapByPlanIds(planIds);
|
||||||
|
Map<String, List<TestPlanApiScenario>> planApiScenarioMap = getApiScenarioByPlanIds(planIds);
|
||||||
|
|
||||||
//查询定时任务
|
//查询定时任务
|
||||||
ScheduleExample scheduleExample = new ScheduleExample();
|
ScheduleExample scheduleExample = new ScheduleExample();
|
||||||
|
@ -99,34 +96,32 @@ public class TestPlanStatisticsService {
|
||||||
List<Schedule> schedules = scheduleMapper.selectByExample(scheduleExample);
|
List<Schedule> schedules = scheduleMapper.selectByExample(scheduleExample);
|
||||||
Map<String, Schedule> scheduleMap = schedules.stream().collect(Collectors.toMap(Schedule::getResourceId, t -> t));
|
Map<String, Schedule> scheduleMap = schedules.stream().collect(Collectors.toMap(Schedule::getResourceId, t -> t));
|
||||||
|
|
||||||
// TODO: 计划-接口用例的关联数据
|
|
||||||
planIds.forEach(planId -> {
|
planIds.forEach(planId -> {
|
||||||
TestPlanStatisticsResponse statisticsResponse = new TestPlanStatisticsResponse();
|
TestPlanStatisticsResponse statisticsResponse = new TestPlanStatisticsResponse();
|
||||||
statisticsResponse.setId(planId);
|
statisticsResponse.setId(planId);
|
||||||
statisticsResponse.setPassThreshold(planConfigMap.get(planId).getPassThreshold());
|
statisticsResponse.setPassThreshold(planConfigMap.get(planId).getPassThreshold());
|
||||||
int success = 0, error = 0, fakeError = 0, block = 0, pending = 0;
|
// 功能用例分组统计开始 (为空时, 默认为未执行)
|
||||||
// 功能用例统计开始
|
|
||||||
List<TestPlanFunctionalCase> functionalCases = planFunctionalCaseMap.get(planId);
|
List<TestPlanFunctionalCase> functionalCases = planFunctionalCaseMap.get(planId);
|
||||||
statisticsResponse.setFunctionalCaseCount(CollectionUtils.isNotEmpty(functionalCases) ? functionalCases.size() : 0);
|
statisticsResponse.setFunctionalCaseCount(CollectionUtils.isNotEmpty(functionalCases) ? functionalCases.size() : 0);
|
||||||
// 根据执行结果分组(为空, 默认为未执行)
|
Map<String, Long> functionalCaseResultCountMap = CollectionUtils.isEmpty(functionalCases) ? new HashMap<>(16) : functionalCases.stream().collect(
|
||||||
Map<String, List<TestPlanFunctionalCase>> functionalCaseResultMap = CollectionUtils.isEmpty(functionalCases) ? new HashMap<>(16) : functionalCases.stream().collect(
|
Collectors.groupingBy(functionalCase -> Optional.ofNullable(functionalCase.getLastExecResult()).orElse(ExecStatus.PENDING.name()), Collectors.counting()));
|
||||||
Collectors.groupingBy(functionalCase -> Optional.ofNullable(functionalCase.getLastExecResult()).orElse(ExecStatus.PENDING.name())));
|
// 接口用例分组统计开始 (为空时, 默认为未执行)
|
||||||
success += functionalCaseResultMap.containsKey(ExecStatus.SUCCESS.name()) ? functionalCaseResultMap.get(ExecStatus.SUCCESS.name()).size() : 0;
|
List<TestPlanApiCase> apiCases = planApiCaseMap.get(planId);
|
||||||
error += functionalCaseResultMap.containsKey(ExecStatus.ERROR.name()) ? functionalCaseResultMap.get(ExecStatus.ERROR.name()).size() : 0;
|
statisticsResponse.setApiCaseCount(CollectionUtils.isNotEmpty(apiCases) ? apiCases.size() : 0);
|
||||||
fakeError += functionalCaseResultMap.containsKey(ExecStatus.FAKE_ERROR.name()) ? functionalCaseResultMap.get(ExecStatus.FAKE_ERROR.name()).size() : 0;
|
Map<String, Long> apiCaseResultCountMap = CollectionUtils.isEmpty(apiCases) ? new HashMap<>(16) : apiCases.stream().collect(
|
||||||
block += functionalCaseResultMap.containsKey(ExecStatus.BLOCKED.name()) ? functionalCaseResultMap.get(ExecStatus.BLOCKED.name()).size() : 0;
|
Collectors.groupingBy(apiCase -> Optional.ofNullable(apiCase.getLastExecResult()).orElse(ExecStatus.PENDING.name()), Collectors.counting()));
|
||||||
pending += functionalCaseResultMap.containsKey(ExecStatus.PENDING.name()) ? functionalCaseResultMap.get(ExecStatus.PENDING.name()).size() : 0;
|
// 接口场景用例分组统计开始 (为空时, 默认为未执行)
|
||||||
// TODO: 接口用例统计开始
|
List<TestPlanApiScenario> apiScenarios = planApiScenarioMap.get(planId);
|
||||||
|
statisticsResponse.setApiScenarioCount(CollectionUtils.isNotEmpty(apiScenarios) ? apiScenarios.size() : 0);
|
||||||
|
Map<String, Long> apiScenarioResultCountMap = CollectionUtils.isEmpty(apiScenarios) ? new HashMap<>(16) : apiScenarios.stream().collect(
|
||||||
|
Collectors.groupingBy(apiScenario -> Optional.ofNullable(apiScenario.getLastExecResult()).orElse(ExecStatus.PENDING.name()), Collectors.counting()));
|
||||||
// 用例数据汇总
|
// 用例数据汇总
|
||||||
statisticsResponse.setSuccessCount(success);
|
statisticsResponse.setSuccessCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ExecStatus.SUCCESS.name()));
|
||||||
statisticsResponse.setErrorCount(error);
|
statisticsResponse.setErrorCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ExecStatus.ERROR.name()));
|
||||||
statisticsResponse.setFakeErrorCount(fakeError);
|
statisticsResponse.setFakeErrorCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ExecStatus.FAKE_ERROR.name()));
|
||||||
statisticsResponse.setBlockCount(block);
|
statisticsResponse.setBlockCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ExecStatus.BLOCKED.name()));
|
||||||
statisticsResponse.setPendingCount(pending);
|
statisticsResponse.setPendingCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ExecStatus.PENDING.name()));
|
||||||
// FIXME: CaseTotal后续会补充接口用例及场景的统计数据
|
statisticsResponse.setCaseTotal(statisticsResponse.getFunctionalCaseCount() + statisticsResponse.getApiCaseCount() + statisticsResponse.getApiScenarioCount());
|
||||||
statisticsResponse.setCaseTotal(statisticsResponse.getFunctionalCaseCount());
|
|
||||||
// 通过率 {通过用例数/总用例数} && 执行进度 {非未执行的用例数/总用例数}
|
// 通过率 {通过用例数/总用例数} && 执行进度 {非未执行的用例数/总用例数}
|
||||||
statisticsResponse.setPassRate(RateCalculateUtils.divWithPrecision(statisticsResponse.getSuccessCount(), statisticsResponse.getCaseTotal(), 2));
|
statisticsResponse.setPassRate(RateCalculateUtils.divWithPrecision(statisticsResponse.getSuccessCount(), statisticsResponse.getCaseTotal(), 2));
|
||||||
statisticsResponse.setExecuteRate(RateCalculateUtils.divWithPrecision(statisticsResponse.getCaseTotal() - statisticsResponse.getPendingCount(), statisticsResponse.getCaseTotal(), 2));
|
statisticsResponse.setExecuteRate(RateCalculateUtils.divWithPrecision(statisticsResponse.getCaseTotal() - statisticsResponse.getPendingCount(), statisticsResponse.getCaseTotal(), 2));
|
||||||
|
@ -151,4 +146,37 @@ public class TestPlanStatisticsService {
|
||||||
});
|
});
|
||||||
return planStatisticsResponses;
|
return planStatisticsResponses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Map<String, List<TestPlanFunctionalCase>> getFunctionalCaseMapByPlanIds(List<String> planIds) {
|
||||||
|
// 计划或者组-功能用例的关联数据
|
||||||
|
List<TestPlanFunctionalCase> planFunctionalCases = extTestPlanFunctionalCaseMapper.getPlanFunctionalCaseByIds(planIds);
|
||||||
|
return planFunctionalCases.stream().collect(Collectors.groupingBy(TestPlanFunctionalCase::getTestPlanId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, List<TestPlanApiCase>> getApiCaseMapByPlanIds(List<String> planIds) {
|
||||||
|
// 计划或者组-接口用例的关联数据
|
||||||
|
List<TestPlanApiCase> planApiCases = extTestPlanApiCaseMapper.getPlanApiCaseByIds(planIds);
|
||||||
|
return planApiCases.stream().collect(Collectors.groupingBy(TestPlanApiCase::getTestPlanId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, List<TestPlanApiScenario>> getApiScenarioByPlanIds(List<String> planIds) {
|
||||||
|
// 计划或者组-场景用例的关联数据
|
||||||
|
List<TestPlanApiScenario> planApiScenarios = extTestPlanApiScenarioMapper.getPlanApiScenarioByIds(planIds);
|
||||||
|
return planApiScenarios.stream().collect(Collectors.groupingBy(TestPlanApiScenario::getTestPlanId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 汇总计划下所有的用例的集合
|
||||||
|
* @param functionalCaseMap 功能用例
|
||||||
|
* @param apiCaseMap 接口用例
|
||||||
|
* @param apiScenarioMap 接口场景
|
||||||
|
* @param countKey 汇总的key
|
||||||
|
* @return 总数
|
||||||
|
*/
|
||||||
|
private Integer countCaseMap(Map<String, Long> functionalCaseMap, Map<String, Long> apiCaseMap, Map<String, Long> apiScenarioMap, String countKey) {
|
||||||
|
return (functionalCaseMap.containsKey(countKey) ? functionalCaseMap.get(countKey).intValue() : 0) +
|
||||||
|
(apiCaseMap.containsKey(countKey) ? apiCaseMap.get(countKey).intValue() : 0) +
|
||||||
|
(apiScenarioMap.containsKey(countKey) ? apiScenarioMap.get(countKey).intValue() : 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,18 @@ INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, r
|
||||||
('oasis_fc_4', 10004, 'TEST_MODULE_ID', 'project-associate-case-test', '100001', '测试', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'v1.0.0', 'BLOCKED', b'0', b'0', b'1', 'admin', 'admin', '', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL),
|
('oasis_fc_4', 10004, 'TEST_MODULE_ID', 'project-associate-case-test', '100001', '测试', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'v1.0.0', 'BLOCKED', b'0', b'0', b'1', 'admin', 'admin', '', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL),
|
||||||
('oasis_fc_5', 10005, 'TEST_MODULE_ID', 'project-associate-case-test', '100001', '测试', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'v1.0.0', 'FAKE_ERROR', b'0', b'0', b'1', 'admin', 'admin', '', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL);
|
('oasis_fc_5', 10005, 'TEST_MODULE_ID', 'project-associate-case-test', '100001', '测试', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'v1.0.0', 'FAKE_ERROR', b'0', b'0', b'1', 'admin', 'admin', '', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL);
|
||||||
|
|
||||||
|
INSERT INTO test_plan_api_case(`id`, `test_plan_id`, `api_case_id`, `environment_id`, `last_exec_result`, `last_exec_report_id`, `execute_user`, `create_time`, `create_user`, `pos`, `test_plan_collection_id`) VALUES
|
||||||
|
('oasis_1', 'wx_test_plan_id_7', 'oasis_ac_1', '1', 'PASSED', NULL, 'admin', 1716370415311, 'admin', 1, '123');
|
||||||
|
|
||||||
|
INSERT INTO api_test_case(id, name, priority, num, tags, status, last_report_status, last_report_id, pos, project_id, api_definition_id, version_id, environment_id, create_time, create_user, update_time, update_user, delete_time, delete_user, deleted) VALUES
|
||||||
|
('oasis_ac_1', 'oasis_ac', 'P0', 1001, null, 'Underway', 'PENDING', null, 100, 'project-associate-case-test', 'oasis_ac_definition', 'oasis_ac_version_id', 'oasis_ac_env_id', 1698058347559, 'admin', 1698058347559, 'admin', null, null, false);
|
||||||
|
|
||||||
|
INSERT INTO test_plan_api_scenario (id, test_plan_id, api_scenario_id, environment_id, execute_user, last_exec_result, last_exec_report_id, create_time, create_user, pos, test_plan_collection_id, grouped) VALUES
|
||||||
|
('oasis_1', 'wx_test_plan_id_7', 'oasis_as_1', '1', 'admin', 'PASSED', NULL, 1716370415311, 'admin', 1, '123', false);
|
||||||
|
|
||||||
|
INSERT INTO api_scenario(id, name, priority, status, last_report_status, last_report_id, num, pos, version_id, ref_id, project_id, module_id, description, tags, create_user, create_time, delete_time, delete_user, update_user, update_time, deleted) VALUES
|
||||||
|
('oasis_as_1', 'oasis_as', 'P0', 'Underway', 'PENDING', null, 1000001, 1, 'oasis_as_version_id', 'as-rid', 'test-associate-pro', 'root', null, null, 'admin', UNIX_TIMESTAMP() * 1000, null, null, 'admin', UNIX_TIMESTAMP() * 1000, false);
|
||||||
|
|
||||||
|
|
||||||
INSERT INTO `test_plan_module`(`id`, `project_id`, `name`, `parent_id`, `pos`, `create_time`, `update_time`, `create_user`, `update_user`)
|
INSERT INTO `test_plan_module`(`id`, `project_id`, `name`, `parent_id`, `pos`, `create_time`, `update_time`, `create_user`, `update_user`)
|
||||||
VALUES ('1', 'songtianyang-fix-wx', 'wx_测试模块名称', 'ROOT', 1, 1714980158000, 1714980158000, 'admin', 'admin');
|
VALUES ('1', 'songtianyang-fix-wx', 'wx_测试模块名称', 'ROOT', 1, 1714980158000, 1714980158000, 'admin', 'admin');
|
||||||
|
@ -72,3 +84,4 @@ INSERT INTO `test_plan_collection`(`id`, `test_plan_id`, `name`, `type`, `enviro
|
||||||
('init_collection-delete-2', 'init_plan_id', '接口功能点', 'API', '1', '1', 1, 'admin', unix_timestamp() * 1000),
|
('init_collection-delete-2', 'init_plan_id', '接口功能点', 'API', '1', '1', 1, 'admin', unix_timestamp() * 1000),
|
||||||
('init_collection-delete-3', 'init_plan_id', '场景功能点', 'SCENARIO', '1', '1', 1, 'admin', unix_timestamp() * 1000),
|
('init_collection-delete-3', 'init_plan_id', '场景功能点', 'SCENARIO', '1', '1', 1, 'admin', unix_timestamp() * 1000),
|
||||||
('init_collection-delete-4', 'init_plan_id', '未知的功能点', 'UNKNOWN', '1', '1', 1, 'admin', unix_timestamp() * 1000);
|
('init_collection-delete-4', 'init_plan_id', '未知的功能点', 'UNKNOWN', '1', '1', 1, 'admin', unix_timestamp() * 1000);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue