feat(测试计划): 新增测试规划脑图获取接口

This commit is contained in:
guoyuqi 2024-06-07 17:06:12 +08:00 committed by Craftsman
parent 4b3a474f1c
commit 3fe1bc68dd
12 changed files with 398 additions and 63 deletions

View File

@ -119,3 +119,11 @@ test_plan_schedule=测试计划-定時任務
test_plan_default_functional_collection_name=基本功能点 test_plan_default_functional_collection_name=基本功能点
test_plan_default_api_collection_name=单接口验证 test_plan_default_api_collection_name=单接口验证
test_plan_default_scenario_collection_name=业务流程验证 test_plan_default_scenario_collection_name=业务流程验证
test_plan.mind.test_plan=测试规划
test_plan.mind.serial=
test_plan.mind.parallel=
test_plan.mind.strip=
test_plan.mind.case_count=用例数
test_plan.mind.environment=环境
test_plan.mind.test_resource_pool=资源池

View File

@ -122,3 +122,10 @@ test_plan_schedule=Test plan schedule
test_plan_default_functional_collection_name=Basic function point test_plan_default_functional_collection_name=Basic function point
test_plan_default_api_collection_name=Single interface verification test_plan_default_api_collection_name=Single interface verification
test_plan_default_scenario_collection_name=Business process verification test_plan_default_scenario_collection_name=Business process verification
test_plan.mind.test_plan=Test plan
test_plan.mind.serial=Serial
test_plan.mind.parallel=Parallel
test_plan.mind.strip=Strip
test_plan.mind.case_count=Count
test_plan.mind.environment=Environment
test_plan.mind.test_resource_pool=Resource pool

View File

@ -122,3 +122,10 @@ test_plan_schedule=测试计划-定時任務
test_plan_default_functional_collection_name=基本功能点 test_plan_default_functional_collection_name=基本功能点
test_plan_default_api_collection_name=单接口验证 test_plan_default_api_collection_name=单接口验证
test_plan_default_scenario_collection_name=业务流程验证 test_plan_default_scenario_collection_name=业务流程验证
test_plan.mind.test_plan=测试规划
test_plan.mind.serial=
test_plan.mind.parallel=
test_plan.mind.strip=
test_plan.mind.case_count=用例数
test_plan.mind.environment=环境
test_plan.mind.test_resource_pool=资源池

View File

@ -121,3 +121,10 @@ test_plan_schedule=測試計劃-定時任務
test_plan_default_functional_collection_name=基本功能點 test_plan_default_functional_collection_name=基本功能點
test_plan_default_api_collection_name=單接口驗證 test_plan_default_api_collection_name=單接口驗證
test_plan_default_scenario_collection_name=業務流程驗證 test_plan_default_scenario_collection_name=業務流程驗證
test_plan.mind.test_plan=測試規劃
test_plan.mind.serial=
test_plan.mind.parallel=
test_plan.mind.strip=
test_plan.mind.case_count=用例數
test_plan.mind.environment=環境
test_plan.mind.test_resource_pool=資源池

View File

@ -294,9 +294,10 @@ public class FunctionalCaseMinderService {
Map<String, String> newModuleMap = new HashMap<>(); Map<String, String> newModuleMap = new HashMap<>();
//处理模块 //处理模块
dealModule(request, userId, moduleMapper, newModuleMap); List<String> moduleNodeIds = dealModule(request, userId, moduleMapper, newModuleMap);
//处理用例 //处理用例
List<String> caseNodeIds = new ArrayList<>();
if (CollectionUtils.isNotEmpty(request.getUpdateCaseList())) { if (CollectionUtils.isNotEmpty(request.getUpdateCaseList())) {
Map<String, List<FunctionalCaseChangeRequest>> resourceMap = request.getUpdateCaseList().stream().collect(Collectors.groupingBy(FunctionalCaseChangeRequest::getType)); Map<String, List<FunctionalCaseChangeRequest>> resourceMap = request.getUpdateCaseList().stream().collect(Collectors.groupingBy(FunctionalCaseChangeRequest::getType));
//处理新增 //处理新增
@ -310,6 +311,7 @@ public class FunctionalCaseMinderService {
FunctionalCase functionalCase = addCase(request, userId, functionalCaseChangeRequest, caseMapper, newModuleMap); FunctionalCase functionalCase = addCase(request, userId, functionalCaseChangeRequest, caseMapper, newModuleMap);
String caseId = functionalCase.getId(); String caseId = functionalCase.getId();
//附属表 //附属表
caseNodeIds.add(caseId);
FunctionalCaseBlob functionalCaseBlob = addCaseBlob(functionalCaseChangeRequest, caseId, caseBlobMapper); FunctionalCaseBlob functionalCaseBlob = addCaseBlob(functionalCaseChangeRequest, caseId, caseBlobMapper);
//保存自定义字段 //保存自定义字段
List<FunctionalCaseCustomField> functionalCaseCustomFields = addCustomFields(functionalCaseChangeRequest, caseId, caseCustomFieldMapper, defaultValueMap); List<FunctionalCaseCustomField> functionalCaseCustomFields = addCustomFields(functionalCaseChangeRequest, caseId, caseCustomFieldMapper, defaultValueMap);
@ -366,16 +368,14 @@ public class FunctionalCaseMinderService {
} }
//批量排序 //批量排序
batchSort(updatePosList, caseMapper); batchSort(updatePosList, caseMapper);
} }
//处理空白节点 //处理空白节点
dealAdditionalNode(request, userId, additionalNodeMapper, newModuleMap); dealAdditionalNode(request, userId, additionalNodeMapper, newModuleMap);
//TODO:删除转换的空白节点 moduleNodeIds.addAll(caseNodeIds);
if (CollectionUtils.isNotEmpty(moduleNodeIds)) {
dealMindAdditionalMode(moduleNodeIds);
}
sqlSession.flushStatements(); sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
@ -553,7 +553,8 @@ public class FunctionalCaseMinderService {
} }
private void dealModule(FunctionalCaseMinderEditRequest request, String userId, FunctionalCaseModuleMapper moduleMapper, Map<String, String> newModuleMap) { private List<String> dealModule(FunctionalCaseMinderEditRequest request, String userId, FunctionalCaseModuleMapper moduleMapper, Map<String, String> newModuleMap) {
List<String> nodeIds = new ArrayList<>();
if (CollectionUtils.isNotEmpty(request.getUpdateModuleList())) { if (CollectionUtils.isNotEmpty(request.getUpdateModuleList())) {
List<FunctionalCaseModule> updatePosList = new ArrayList<>(); List<FunctionalCaseModule> updatePosList = new ArrayList<>();
//处理新增 //处理新增
@ -573,6 +574,7 @@ public class FunctionalCaseMinderService {
if (StringUtils.isNotBlank(newModuleMap.get(module.getParentId()))) { if (StringUtils.isNotBlank(newModuleMap.get(module.getParentId()))) {
module.setParentId(newModuleMap.get(module.getParentId())); module.setParentId(newModuleMap.get(module.getParentId()));
} }
nodeIds.add(module.getId());
moduleMapper.insert(module); moduleMapper.insert(module);
} }
parentModuleMap.forEach((k, v) -> { parentModuleMap.forEach((k, v) -> {
@ -584,7 +586,7 @@ public class FunctionalCaseMinderService {
List<FunctionalCaseModuleEditRequest> updateList = resourceMap.get(OperationLogType.UPDATE.toString()); List<FunctionalCaseModuleEditRequest> updateList = resourceMap.get(OperationLogType.UPDATE.toString());
if (CollectionUtils.isNotEmpty(updateList)) { if (CollectionUtils.isNotEmpty(updateList)) {
List<FunctionalCaseModule> modules = new ArrayList<>(); List<FunctionalCaseModule> modules = new ArrayList<>();
Map<String, List<FunctionalCaseModule>> parentModuleMap = getParentModuleMap(addList); Map<String, List<FunctionalCaseModule>> parentModuleMap = getParentModuleMap(updateList);
for (FunctionalCaseModuleEditRequest functionalCaseModuleEditRequest : updateList) { for (FunctionalCaseModuleEditRequest functionalCaseModuleEditRequest : updateList) {
checkModules(functionalCaseModuleEditRequest, parentModuleMap); checkModules(functionalCaseModuleEditRequest, parentModuleMap);
FunctionalCaseModule updateModule = updateModule(userId, functionalCaseModuleEditRequest, moduleMapper); FunctionalCaseModule updateModule = updateModule(userId, functionalCaseModuleEditRequest, moduleMapper);
@ -604,6 +606,7 @@ public class FunctionalCaseMinderService {
//批量排序 //批量排序
batchSortModule(updatePosList, moduleMapper); batchSortModule(updatePosList, moduleMapper);
} }
return nodeIds;
} }
private static void batchSortModule(List<FunctionalCaseModule> updatePosList, FunctionalCaseModuleMapper moduleMapper) { private static void batchSortModule(List<FunctionalCaseModule> updatePosList, FunctionalCaseModuleMapper moduleMapper) {
@ -1038,12 +1041,16 @@ public class FunctionalCaseMinderService {
List<MinderOptionDTO> additionalOptionDTOS = resourceMap.get(ModuleConstants.ROOT_NODE_PARENT_ID); List<MinderOptionDTO> additionalOptionDTOS = resourceMap.get(ModuleConstants.ROOT_NODE_PARENT_ID);
if (CollectionUtils.isNotEmpty(additionalOptionDTOS)) { if (CollectionUtils.isNotEmpty(additionalOptionDTOS)) {
List<String> mindAdditionalNodeIds = caseModuleOptionDTOS.stream().map(MinderOptionDTO::getId).toList(); List<String> mindAdditionalNodeIds = caseModuleOptionDTOS.stream().map(MinderOptionDTO::getId).toList();
dealMindAdditionalMode(mindAdditionalNodeIds);
}
}
}
private void dealMindAdditionalMode(List<String> mindAdditionalNodeIds) {
MindAdditionalNodeExample mindAdditionalNodeExample = new MindAdditionalNodeExample(); MindAdditionalNodeExample mindAdditionalNodeExample = new MindAdditionalNodeExample();
mindAdditionalNodeExample.createCriteria().andIdIn(mindAdditionalNodeIds); mindAdditionalNodeExample.createCriteria().andIdIn(mindAdditionalNodeIds);
mindAdditionalNodeMapper.deleteByExample(mindAdditionalNodeExample); mindAdditionalNodeMapper.deleteByExample(mindAdditionalNodeExample);
} }
}
}
public List<FunctionalMinderTreeDTO> getReviewMindFunctionalCase(FunctionalCaseReviewMindRequest request, boolean deleted, String userId, String viewStatusUserId) { public List<FunctionalMinderTreeDTO> getReviewMindFunctionalCase(FunctionalCaseReviewMindRequest request, boolean deleted, String userId, String viewStatusUserId) {

View File

@ -0,0 +1,34 @@
package io.metersphere.plan.controller;
import io.metersphere.plan.dto.TestPlanCollectionMinderTreeDTO;
import io.metersphere.plan.service.TestPlanCollectionMinderService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.security.CheckOwner;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Tag(name = "测试规划脑图")
@RestController
@RequestMapping("/test-plan/mind")
public class TestPlanCollectionMinderController {
@Resource
private TestPlanCollectionMinderService testPlanCollectionMinderService;
@GetMapping("/data/{planId}")
@Operation(summary = "测试规划脑图列表")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ_UPDATE)
@CheckOwner(resourceId = "#planId", resourceType = "test_plan")
public List<TestPlanCollectionMinderTreeDTO> getMindTestPlanCase(@PathVariable String planId) {
return testPlanCollectionMinderService.getMindTestPlanCase(planId);
}
}

View File

@ -34,4 +34,34 @@ public class TestPlanCollectionMinderTreeNodeDTO {
@Schema(description = "节点状态") @Schema(description = "节点状态")
private String expandState = "expand"; private String expandState = "expand";
@Schema(description = "测试集类型(功能/接口/场景)", requiredMode = Schema.RequiredMode.REQUIRED)
private String type;
@Schema(description = "是否继承", requiredMode = Schema.RequiredMode.REQUIRED)
private Boolean extended;
@Schema(description = "是否使用环境组", requiredMode = Schema.RequiredMode.REQUIRED)
private Boolean grouped;
@Schema(description = "环境ID/环境组ID", requiredMode = Schema.RequiredMode.REQUIRED)
private String environmentId;
@Schema(description = "测试资源池ID", requiredMode = Schema.RequiredMode.REQUIRED)
private String testResourcePoolId;
@Schema(description = "是否失败重试", requiredMode = Schema.RequiredMode.REQUIRED)
private Boolean retryOnFail;
@Schema(description = "失败重试类型(步骤/场景)", requiredMode = Schema.RequiredMode.REQUIRED)
private String retryType;
@Schema(description = "失败重试次数", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer retryTimes;
@Schema(description = "失败重试间隔(单位: ms)", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer retryInterval;
@Schema(description = "是否失败停止", requiredMode = Schema.RequiredMode.REQUIRED)
private Boolean stopOnFail;
} }

View File

@ -0,0 +1,12 @@
package io.metersphere.plan.mapper;
import io.metersphere.plan.dto.TestPlanCollectionConfigDTO;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtTestPlanCollectionMapper {
List<TestPlanCollectionConfigDTO> getList(@Param("planId") String planId);
}

View File

@ -0,0 +1,23 @@
<?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="io.metersphere.plan.mapper.ExtTestPlanCollectionMapper">
<select id="getList" resultType="io.metersphere.plan.dto.TestPlanCollectionConfigDTO">
SELECT
tpc.id, tpc.test_plan_id, tpc.parent_id,
tpc.`name`, tpc.`type`, tpc.execute_method,
tpc.extended, tpc.grouped, tpc.environment_id,
tpc.test_resource_pool_id, tpc.retry_on_fail, tpc.retry_type,
tpc.retry_times, tpc.retry_interval, tpc.stop_on_fail,
tpc.create_user, tpc.create_time, tpc.pos,
trp.name as poolName,
IF(env.name is not null, env.name, envg.name) as envName
FROM
test_plan_collection tpc
LEFT JOIN test_resource_pool trp ON tpc.test_resource_pool_id = trp.id
LEFT JOIN environment env ON tpc.environment_id = env.id
LEFT JOIN environment_group envg ON tpc.test_resource_pool_id = envg.id
WHERE tpc.test_plan_id = #{planId}
</select>
</mapper>

View File

@ -1,101 +1,220 @@
package io.metersphere.plan.service; package io.metersphere.plan.service;
import io.metersphere.plan.domain.TestPlanCollection; import io.metersphere.plan.domain.*;
import io.metersphere.plan.domain.TestPlanCollectionExample; import io.metersphere.plan.dto.TestPlanCollectionConfigDTO;
import io.metersphere.plan.dto.TestPlanCollectionMinderTreeDTO; import io.metersphere.plan.dto.TestPlanCollectionMinderTreeDTO;
import io.metersphere.plan.dto.TestPlanCollectionMinderTreeNodeDTO; import io.metersphere.plan.dto.TestPlanCollectionMinderTreeNodeDTO;
import io.metersphere.plan.mapper.TestPlanCollectionMapper; import io.metersphere.plan.mapper.ExtTestPlanCollectionMapper;
import io.metersphere.plan.mapper.TestPlanApiCaseMapper;
import io.metersphere.plan.mapper.TestPlanApiScenarioMapper;
import io.metersphere.plan.mapper.TestPlanFunctionalCaseMapper;
import io.metersphere.sdk.constants.ApiBatchRunMode; import io.metersphere.sdk.constants.ApiBatchRunMode;
import io.metersphere.sdk.constants.CaseType;
import io.metersphere.sdk.constants.ModuleConstants; import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.Translator;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList; import java.util.*;
import java.util.Comparator; import java.util.stream.Collectors;
import java.util.List;
@Service @Service
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public class TestPlanCollectionMinderService { public class TestPlanCollectionMinderService {
@Resource @Resource
private TestPlanCollectionMapper testPlanCollectionMapper; private ExtTestPlanCollectionMapper extTestPlanCollectionMapper;
@Resource
private TestPlanFunctionalCaseMapper testPlanFunctionalCaseMapper;
@Resource
private TestPlanApiCaseMapper testPlanApiCaseMapper;
@Resource
private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
/** /**
* 测试计划-脑图用例列表查询 * 测试计划-脑图用例列表查询
* *
* @return FunctionalMinderTreeDTO * @return FunctionalMinderTreeDTO
*/ */
public List<TestPlanCollectionMinderTreeDTO> getMindFunctionalCase(String planId) { public List<TestPlanCollectionMinderTreeDTO> getMindTestPlanCase(String planId) {
List<TestPlanCollectionMinderTreeDTO> list = new ArrayList<>(); List<TestPlanCollectionMinderTreeDTO> list = new ArrayList<>();
TestPlanCollectionExample testPlanCollectionExample = new TestPlanCollectionExample(); List<TestPlanCollectionConfigDTO> testPlanCollections = extTestPlanCollectionMapper.getList(planId);
testPlanCollectionExample.createCriteria().andTestPlanIdEqualTo(planId); //构造根节点
List<TestPlanCollection> testPlanCollections = testPlanCollectionMapper.selectByExample(testPlanCollectionExample);
TestPlanCollectionMinderTreeNodeDTO testPlanCollectionMinderTreeNodeDTO = buildRoot(); TestPlanCollectionMinderTreeNodeDTO testPlanCollectionMinderTreeNodeDTO = buildRoot();
//
TestPlanCollectionMinderTreeDTO testPlanCollectionMinderTreeDTO = new TestPlanCollectionMinderTreeDTO(); TestPlanCollectionMinderTreeDTO testPlanCollectionMinderTreeDTO = new TestPlanCollectionMinderTreeDTO();
testPlanCollectionMinderTreeDTO.setData(testPlanCollectionMinderTreeNodeDTO); testPlanCollectionMinderTreeDTO.setData(testPlanCollectionMinderTreeNodeDTO);
//构造type节点
List<TestPlanCollectionMinderTreeDTO> children = new ArrayList<>(); List<TestPlanCollectionMinderTreeDTO> children = new ArrayList<>();
List<TestPlanCollection> parentList = testPlanCollections.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getParentId(), ModuleConstants.ROOT_NODE_PARENT_ID)).sorted(Comparator.comparing(TestPlanCollection::getPos)).toList(); List<TestPlanCollectionConfigDTO> parentList = testPlanCollections.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getParentId(), ModuleConstants.ROOT_NODE_PARENT_ID)).sorted(Comparator.comparing(TestPlanCollection::getPos)).toList();
buildTypeChildren(parentList, testPlanCollections, children); buildTypeChildren(parentList, testPlanCollections, children);
testPlanCollectionMinderTreeDTO.setChildren(children); testPlanCollectionMinderTreeDTO.setChildren(children);
list.add(testPlanCollectionMinderTreeDTO); list.add(testPlanCollectionMinderTreeDTO);
return list; return list;
} }
private static void buildTypeChildren(List<TestPlanCollection> parentList, List<TestPlanCollection> testPlanCollections, List<TestPlanCollectionMinderTreeDTO> children) { private void buildTypeChildren(List<TestPlanCollectionConfigDTO> parentList, List<TestPlanCollectionConfigDTO> testPlanCollections, List<TestPlanCollectionMinderTreeDTO> children) {
for (TestPlanCollection testPlanCollection : parentList) { for (TestPlanCollection testPlanCollection : parentList) {
TestPlanCollectionMinderTreeDTO treeDTO = new TestPlanCollectionMinderTreeDTO(); TestPlanCollectionMinderTreeDTO typeTreeDTO = new TestPlanCollectionMinderTreeDTO();
TestPlanCollectionMinderTreeNodeDTO typeTreeNodeDTO = new TestPlanCollectionMinderTreeNodeDTO(); TestPlanCollectionMinderTreeNodeDTO typeTreeNodeDTO = buildTypeChildData(testPlanCollection);
typeTreeNodeDTO.setId(testPlanCollection.getId()); //构造子节点
typeTreeNodeDTO.setText(testPlanCollection.getName());
typeTreeNodeDTO.setPos(testPlanCollection.getPos());
if (StringUtils.equalsIgnoreCase(testPlanCollection.getExecuteMethod(), ApiBatchRunMode.PARALLEL.toString())) {
typeTreeNodeDTO.setPriority("");
} else {
typeTreeNodeDTO.setPriority("");
}
typeTreeNodeDTO.setExecuteMethod(testPlanCollection.getExecuteMethod());
List<TestPlanCollectionMinderTreeDTO> collectionChildren = new ArrayList<>(); List<TestPlanCollectionMinderTreeDTO> collectionChildren = new ArrayList<>();
List<TestPlanCollection> childrenList = testPlanCollections.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getParentId(), testPlanCollection.getId())).sorted(Comparator.comparing(TestPlanCollection::getPos)).toList(); List<TestPlanCollectionConfigDTO> childrenList = testPlanCollections.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getParentId(), testPlanCollection.getId())).sorted(Comparator.comparing(TestPlanCollection::getPos)).toList();
buildCollectionChildren(childrenList, collectionChildren); Map<String, List<TestPlanCollectionConfigDTO>> typeChildren = childrenList.stream().collect(Collectors.groupingBy(TestPlanCollectionConfigDTO::getType));
treeDTO.setData(typeTreeNodeDTO); Map<String, List<TestPlanFunctionalCase>> testPlanFunctionalCaseMap = getTestPlanFunctionalCases(typeChildren);
treeDTO.setChildren(collectionChildren); Map<String, List<TestPlanApiCase>> testPlanApiCaseMap = getTestPlanApiCases(typeChildren);
children.add(treeDTO); Map<String, List<TestPlanApiScenario>> testPlanApiScenarioMap = getTestPlanApiScenarios(typeChildren);
buildCollectionChildren(childrenList, collectionChildren, testPlanFunctionalCaseMap, testPlanApiCaseMap, testPlanApiScenarioMap);
typeTreeDTO.setData(typeTreeNodeDTO);
typeTreeDTO.setChildren(collectionChildren);
children.add(typeTreeDTO);
} }
} }
private static void buildCollectionChildren(List<TestPlanCollection> childrenList, List<TestPlanCollectionMinderTreeDTO> collectionChildren) { @NotNull
for (TestPlanCollection planCollection : childrenList) { private static TestPlanCollectionMinderTreeNodeDTO buildTypeChildData(TestPlanCollection testPlanCollection) {
TestPlanCollectionMinderTreeDTO collectionTreeDTO = new TestPlanCollectionMinderTreeDTO(); TestPlanCollectionMinderTreeNodeDTO typeTreeNodeDTO = new TestPlanCollectionMinderTreeNodeDTO();
TestPlanCollectionMinderTreeNodeDTO collectionTreeNodeDTO = new TestPlanCollectionMinderTreeNodeDTO(); BeanUtils.copyBean(typeTreeNodeDTO, testPlanCollection);
collectionTreeNodeDTO.setId(planCollection.getId()); typeTreeNodeDTO.setText(testPlanCollection.getName());
collectionTreeNodeDTO.setText(planCollection.getName()); if (StringUtils.equalsIgnoreCase(testPlanCollection.getExecuteMethod(), ApiBatchRunMode.PARALLEL.toString())) {
collectionTreeNodeDTO.setPos(planCollection.getPos()); typeTreeNodeDTO.setPriority(Translator.get("test_plan.mind.serial"));
if (StringUtils.equalsIgnoreCase(planCollection.getExecuteMethod(), ApiBatchRunMode.PARALLEL.toString())) {
collectionTreeNodeDTO.setPriority("");
} else { } else {
collectionTreeNodeDTO.setPriority(""); typeTreeNodeDTO.setPriority(Translator.get("test_plan.mind.parallel"));
} }
collectionTreeNodeDTO.setExecuteMethod(planCollection.getExecuteMethod()); return typeTreeNodeDTO;
}
private Map<String, List<TestPlanApiScenario>> getTestPlanApiScenarios(Map<String, List<TestPlanCollectionConfigDTO>> typeChildren) {
List<TestPlanCollectionConfigDTO> testPlanCollectionConfigDTOS = typeChildren.get(CaseType.SCENARIO_CASE.getKey());
if (CollectionUtils.isEmpty(testPlanCollectionConfigDTOS)) {
return new HashMap<>();
}
List<String> scenarioCollectIds = testPlanCollectionConfigDTOS.stream().map(TestPlanCollectionConfigDTO::getId).toList();
TestPlanApiScenarioExample testPlanApiScenarioExample = new TestPlanApiScenarioExample();
testPlanApiScenarioExample.createCriteria().andTestPlanCollectionIdIn(scenarioCollectIds);
List<TestPlanApiScenario> testPlanApiScenarios = testPlanApiScenarioMapper.selectByExample(testPlanApiScenarioExample);
return testPlanApiScenarios.stream().collect(Collectors.groupingBy(TestPlanApiScenario::getTestPlanCollectionId));
}
private Map<String, List<TestPlanApiCase>> getTestPlanApiCases(Map<String, List<TestPlanCollectionConfigDTO>> typeChildren) {
List<TestPlanCollectionConfigDTO> testPlanCollectionConfigDTOS = typeChildren.get(CaseType.API_CASE.getKey());
if (CollectionUtils.isEmpty(testPlanCollectionConfigDTOS)) {
return new HashMap<>();
}
List<String> apiCollectIds = testPlanCollectionConfigDTOS.stream().map(TestPlanCollectionConfigDTO::getId).toList();
TestPlanApiCaseExample testPlanApiCaseExample = new TestPlanApiCaseExample();
testPlanApiCaseExample.createCriteria().andTestPlanCollectionIdIn(apiCollectIds);
List<TestPlanApiCase> testPlanApiCases = testPlanApiCaseMapper.selectByExample(testPlanApiCaseExample);
return testPlanApiCases.stream().collect(Collectors.groupingBy(TestPlanApiCase::getTestPlanCollectionId));
}
private Map<String, List<TestPlanFunctionalCase>> getTestPlanFunctionalCases(Map<String, List<TestPlanCollectionConfigDTO>> typeChildren) {
List<TestPlanCollectionConfigDTO> testPlanCollectionConfigDTOS = typeChildren.get(CaseType.FUNCTIONAL_CASE.getKey());
if (CollectionUtils.isEmpty(testPlanCollectionConfigDTOS)) {
return new HashMap<>();
}
List<String> functionalCollectIds = testPlanCollectionConfigDTOS.stream().map(TestPlanCollectionConfigDTO::getId).toList();
TestPlanFunctionalCaseExample testPlanFunctionalCaseExample = new TestPlanFunctionalCaseExample();
testPlanFunctionalCaseExample.createCriteria().andTestPlanCollectionIdIn(functionalCollectIds);
List<TestPlanFunctionalCase> testPlanFunctionalCases = testPlanFunctionalCaseMapper.selectByExample(testPlanFunctionalCaseExample);
return testPlanFunctionalCases.stream().collect(Collectors.groupingBy(TestPlanFunctionalCase::getTestPlanCollectionId));
}
private void buildCollectionChildren(List<TestPlanCollectionConfigDTO> childrenList, List<TestPlanCollectionMinderTreeDTO> collectionChildren, Map<String, List<TestPlanFunctionalCase>> testPlanFunctionalCaseMap, Map<String, List<TestPlanApiCase>> testPlanApiCaseMap, Map<String, List<TestPlanApiScenario>> testPlanApiScenarioMap) {
for (TestPlanCollectionConfigDTO planCollection : childrenList) {
TestPlanCollectionMinderTreeDTO collectionTreeDTO = new TestPlanCollectionMinderTreeDTO();
TestPlanCollectionMinderTreeNodeDTO collectionTreeNodeDTO = buildTypeChildData(planCollection);
collectionTreeNodeDTO.setResource(new ArrayList<>()); collectionTreeNodeDTO.setResource(new ArrayList<>());
//TODO:构造子集 List<TestPlanCollectionMinderTreeDTO> endList = getEndList(testPlanFunctionalCaseMap, testPlanApiCaseMap, testPlanApiScenarioMap, planCollection);
collectionTreeDTO.setData(collectionTreeNodeDTO); collectionTreeDTO.setData(collectionTreeNodeDTO);
collectionTreeDTO.setChildren(new ArrayList<>()); collectionTreeDTO.setChildren(endList);
collectionChildren.add(collectionTreeDTO); collectionChildren.add(collectionTreeDTO);
} }
} }
@NotNull
private static List<TestPlanCollectionMinderTreeDTO> getEndList(Map<String, List<TestPlanFunctionalCase>> testPlanFunctionalCaseMap, Map<String, List<TestPlanApiCase>> testPlanApiCaseMap, Map<String, List<TestPlanApiScenario>> testPlanApiScenarioMap, TestPlanCollectionConfigDTO planCollection) {
List<TestPlanCollectionMinderTreeDTO> endList = new ArrayList<>();
if (StringUtils.equalsIgnoreCase(planCollection.getType(), CaseType.FUNCTIONAL_CASE.getKey())) {
buildFunctionalChild(testPlanFunctionalCaseMap, planCollection, endList);
} else if (StringUtils.equalsIgnoreCase(planCollection.getType(), CaseType.API_CASE.getKey())) {
buildApiCaseChild(testPlanApiCaseMap, planCollection, endList);
} else {
buildScenarioChild(testPlanApiScenarioMap, planCollection, endList);
}
return endList;
}
private static void buildScenarioChild(Map<String, List<TestPlanApiScenario>> testPlanApiScenarioMap, TestPlanCollectionConfigDTO planCollection, List<TestPlanCollectionMinderTreeDTO> endList) {
TestPlanCollectionMinderTreeDTO countTreeDTO = new TestPlanCollectionMinderTreeDTO();
TestPlanCollectionMinderTreeNodeDTO countTreeNodeDTO = new TestPlanCollectionMinderTreeNodeDTO();
List<TestPlanApiScenario> testPlanApiScenarios = testPlanApiScenarioMap.get(planCollection.getId());
int count = 0;
if (CollectionUtils.isNotEmpty(testPlanApiScenarios)) {
count = testPlanApiScenarios.size();
}
buildChild(countTreeNodeDTO, count + Translator.get("test_plan.mind.strip"), "test_plan.mind.case_count", countTreeDTO, endList);
TestPlanCollectionMinderTreeDTO envTreeDTO = new TestPlanCollectionMinderTreeDTO();
TestPlanCollectionMinderTreeNodeDTO envTreeNodeDTO = new TestPlanCollectionMinderTreeNodeDTO();
buildChild(envTreeNodeDTO, planCollection.getEnvName(), "test_plan.mind.environment", envTreeDTO, endList);
TestPlanCollectionMinderTreeDTO poolTreeDTO = new TestPlanCollectionMinderTreeDTO();
TestPlanCollectionMinderTreeNodeDTO poolTreeNodeDTO = new TestPlanCollectionMinderTreeNodeDTO();
buildChild(poolTreeNodeDTO, planCollection.getPoolName(), "test_plan.mind.test_resource_pool", poolTreeDTO, endList);
}
private static void buildChild(TestPlanCollectionMinderTreeNodeDTO treeNodeDTO, String text, String key, TestPlanCollectionMinderTreeDTO treeDTO, List<TestPlanCollectionMinderTreeDTO> endList) {
treeNodeDTO.setText(text);
treeNodeDTO.setResource(List.of(Translator.get(key)));
treeDTO.setData(treeNodeDTO);
treeDTO.setChildren(new ArrayList<>());
if (StringUtils.isNotBlank(text)) {
endList.add(treeDTO);
}
}
private static void buildApiCaseChild(Map<String, List<TestPlanApiCase>> testPlanApiCaseMap, TestPlanCollectionConfigDTO planCollection, List<TestPlanCollectionMinderTreeDTO> endList) {
TestPlanCollectionMinderTreeDTO countTreeDTO = new TestPlanCollectionMinderTreeDTO();
TestPlanCollectionMinderTreeNodeDTO countTreeNodeDTO = new TestPlanCollectionMinderTreeNodeDTO();
List<TestPlanApiCase> testPlanApiCases = testPlanApiCaseMap.get(planCollection.getId());
int count = 0;
if (CollectionUtils.isNotEmpty(testPlanApiCases)) {
count = testPlanApiCases.size();
}
buildChild(countTreeNodeDTO, count + Translator.get("test_plan.mind.strip"), "test_plan.mind.case_count", countTreeDTO, endList);
TestPlanCollectionMinderTreeDTO envTreeDTO = new TestPlanCollectionMinderTreeDTO();
TestPlanCollectionMinderTreeNodeDTO envTreeNodeDTO = new TestPlanCollectionMinderTreeNodeDTO();
buildChild(envTreeNodeDTO, planCollection.getEnvName(), "test_plan.mind.environment", envTreeDTO, endList);
TestPlanCollectionMinderTreeDTO poolTreeDTO = new TestPlanCollectionMinderTreeDTO();
TestPlanCollectionMinderTreeNodeDTO poolTreeNodeDTO = new TestPlanCollectionMinderTreeNodeDTO();
buildChild(poolTreeNodeDTO, planCollection.getPoolName(), "test_plan.mind.test_resource_pool", poolTreeDTO, endList);
}
private static void buildFunctionalChild(Map<String, List<TestPlanFunctionalCase>> testPlanFunctionalCaseMap, TestPlanCollectionConfigDTO planCollection, List<TestPlanCollectionMinderTreeDTO> endList) {
List<TestPlanFunctionalCase> testPlanFunctionalCases = testPlanFunctionalCaseMap.get(planCollection.getId());
int count = 0;
if (CollectionUtils.isNotEmpty(testPlanFunctionalCases)) {
count = testPlanFunctionalCases.size();
}
TestPlanCollectionMinderTreeDTO countTreeDTO = new TestPlanCollectionMinderTreeDTO();
TestPlanCollectionMinderTreeNodeDTO countTreeNodeDTO = new TestPlanCollectionMinderTreeNodeDTO();
buildChild(countTreeNodeDTO, count + Translator.get("test_plan.mind.strip"), "test_plan.mind.case_count", countTreeDTO, endList);
}
@NotNull @NotNull
private static TestPlanCollectionMinderTreeNodeDTO buildRoot() { private static TestPlanCollectionMinderTreeNodeDTO buildRoot() {
TestPlanCollectionMinderTreeNodeDTO testPlanCollectionMinderTreeNodeDTO = new TestPlanCollectionMinderTreeNodeDTO(); TestPlanCollectionMinderTreeNodeDTO testPlanCollectionMinderTreeNodeDTO = new TestPlanCollectionMinderTreeNodeDTO();
testPlanCollectionMinderTreeNodeDTO.setId(ModuleConstants.DEFAULT_NODE_ID); testPlanCollectionMinderTreeNodeDTO.setId(ModuleConstants.DEFAULT_NODE_ID);
testPlanCollectionMinderTreeNodeDTO.setText("测试规划"); testPlanCollectionMinderTreeNodeDTO.setText(Translator.get("test_plan.mind.test_plan"));
testPlanCollectionMinderTreeNodeDTO.setResource(new ArrayList<>()); testPlanCollectionMinderTreeNodeDTO.setResource(new ArrayList<>());
return testPlanCollectionMinderTreeNodeDTO; return testPlanCollectionMinderTreeNodeDTO;
} }

View File

@ -0,0 +1,41 @@
package io.metersphere.plan.controller;
import io.metersphere.plan.dto.TestPlanCollectionMinderTreeDTO;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.test.web.servlet.MvcResult;
import java.nio.charset.StandardCharsets;
import java.util.List;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@AutoConfigureMockMvc
public class TestPlanCollectionMinderControllerTests extends BaseTest {
private static final String PLAN_MIND = "/test-plan/mind/data/";
@Test
@Order(1)
@Sql(scripts = {"/dml/init_test_plan_mind.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
void tesPagePlanReportSuccess() throws Exception {
MvcResult mvcResult = this.requestGetWithOkAndReturn(PLAN_MIND+"gyq_plan_1");
// 获取返回值
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
// 返回请求正常
Assertions.assertNotNull(resultHolder);
List<TestPlanCollectionMinderTreeDTO> testPlanCollectionMinderTreeDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), TestPlanCollectionMinderTreeDTO.class);
// 返回值不为空
Assertions.assertNotNull(testPlanCollectionMinderTreeDTOS);
}
}

View File

@ -0,0 +1,40 @@
INSERT INTO `test_plan`(`id`, `num`, `project_id`, `group_id`, `module_id`, `name`, `status`, `type`, `tags`, `create_time`, `create_user`, `update_time`, `update_user`, `planned_start_time`, `planned_end_time`, `actual_start_time`, `actual_end_time`, `description`)
VALUES
('gyq_plan_1', 5000, 'gyq_plan_project', 'NONE', '1', 'qwe', 'PREPARED', 'TEST_PLAN', NULL, 1714980158000, 'admin', 1714980158000, 'admin', 1714980158000, 1714980158000, 1714980158000, 1714980158000, '11'),
('gyq_plan_2', 10000, 'gyq_plan_project', 'NONE', '1', 'eeew', 'PREPARED', 'TEST_PLAN', NULL, 1714980158000, 'admin', 1714980158000, 'admin', 1714980158000, 1714980158000, 1714980158000, 1714980158000, '11');
INSERT INTO project (id, num, organization_id, name, description, create_user, update_user, create_time, update_time)
VALUES ('gyq_plan_project', null, 'organization-associate-case-test', '用例评论项目', '系统默认创建的项目',
'admin', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
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, last_exec_time)
VALUES ('gyq_wxxx_1', 'gyq_plan_1', 'wxxx_api_case_1', 'gyq_123', NULL, NULL, 'admin', 1716370415311, 'admin', 2, 'gyq_wxxx_4', 1716370415311);
INSERT INTO `test_plan_functional_case`(id, test_plan_id, functional_case_id, create_time, create_user, execute_user, last_exec_time, last_exec_result, pos, test_plan_collection_id)
VALUES('gyq_functional_case_1', 'gyq_plan_1', 'functional_case_id', 1716797474979, 'admin', 'admin', 1716866691313, 'SUCCESS', 4096, 'gyq_wxxx_5');
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, last_exec_time)
VALUES ('gyq_scenario_case_1', 'gyq_plan_1', 'api_scenario_id', 'gyq_123','admin', 'SUCCESS', 'last_exec_report_id', 1716866691313,'admin', 4096, 'gyq_wxxx_6', b'0', 1716866691313);
INSERT INTO `test_plan_collection`(`id`, `test_plan_id`, `name`, `type`, `environment_id`, `test_resource_pool_id`, `pos`, `create_user`, `create_time`, `parent_id`)
VALUES
('gyq_wxxx_1', 'gyq_plan_1', '接口用例', 'API', 'NONE', 'gyq_123_pool', 1, 'admin', 1716370415311, 'NONE'),
('gyq_wxxx_2', 'gyq_plan_1', '功能用例', 'FUNCTIONAL', 'gyq_123', 'gyq_123_pool', 2, 'admin', 1716370415311, 'NONE'),
('gyq_wxxx_3', 'gyq_plan_1', '场景用例', 'SCENARIO', 'NONE', 'NONE', 3, 'admin', 1716370415311, 'NONE'),
('gyq_wxxx_4', 'gyq_plan_1', '接口测试集', 'API', 'NONE', 'gyq_123_pool', 1, 'admin', 1716370415311, 'gyq_wxxx_1'),
('gyq_wxxx_5', 'gyq_plan_1', '功能测试集', 'FUNCTIONAL', 'gyq_123', 'gyq_123_pool', 2, 'admin', 1716370415311, 'gyq_wxxx_2'),
('gyq_wxxx_6', 'gyq_plan_1', '场景测试集', 'SCENARIO', 'NONE', 'gyq_123_pool', 3, 'admin', 1716370415311, 'gyq_wxxx_3');
INSERT INTO `environment`(`id`, `name`, `project_id`, `create_user`, `update_user`, `create_time`, `update_time`, `mock`, `description`, `pos`)
VALUES ('gyq_123', 'Mock环境', 'wxx_1234', 'admin', 'admin', 1716175907000, 1716175907000, b'1', NULL, 64);
INSERT INTO test_resource_pool (id, name, type, description, enable, create_time, update_time, create_user, all_org, deleted)
VALUES ('gyq_123_pool', '默认资源池', 'Node', '系统初始化资源池', true, UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', true, false);