feat(测试计划): 已关联用例模块树统计

This commit is contained in:
WangXu10 2024-05-11 16:31:17 +08:00 committed by Craftsman
parent 2b8486732d
commit 5cf923b55c
8 changed files with 124 additions and 5 deletions

View File

@ -1,7 +1,9 @@
package io.metersphere.plan.controller;
import com.alibaba.excel.util.StringUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.functional.request.ReviewFunctionalCasePageRequest;
import io.metersphere.plan.constants.TestPlanResourceConfig;
import io.metersphere.plan.dto.request.ResourceSortRequest;
import io.metersphere.plan.dto.request.TestPlanAssociationRequest;
@ -28,6 +30,7 @@ import org.springframework.web.bind.annotation.*;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@RestController
@Tag(name = "测试计划功能用例")
@ -61,7 +64,7 @@ public class TestPlanFunctionalCaseController {
@PostMapping("/page")
@Operation(summary = "测试计划-已关联功能用例分页查询")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ)
@CheckOwner(resourceId = "#request.getProjectId()", resourceType = "project")
@CheckOwner(resourceId = "#request.getTestPlanId()", resourceType = "test_plan")
public Pager<List<TestPlanCasePageResponse>> page(@Validated @RequestBody TestPlanCaseRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize());
return PageUtils.setPageInfo(page, testPlanFunctionalCaseService.getFunctionalCasePage(request, false));
@ -76,4 +79,11 @@ public class TestPlanFunctionalCaseController {
return testPlanFunctionalCaseService.getTree(testPlanId);
}
@PostMapping("/module/count")
@Operation(summary = "测试计划-已关联功能用例模块数量")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_READ)
@CheckOwner(resourceId = "#request.getTestPlanId()", resourceType = "test_plan")
public Map<String, Long> moduleCount(@Validated @RequestBody TestPlanCaseRequest request) {
return testPlanFunctionalCaseService.moduleCount(request);
}
}

View File

@ -17,6 +17,10 @@ public class TestPlanCaseRequest extends BasePageRequest implements Serializable
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "测试计划id")
@NotBlank(message = "{test_plan.id.not_blank}")
private String testPlanId;
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{functional_case.project_id.not_blank}")
private String projectId;

View File

@ -1,5 +1,6 @@
package io.metersphere.plan.mapper;
import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO;
import io.metersphere.functional.dto.FunctionalCaseModuleDTO;
import io.metersphere.functional.dto.ProjectOptionDTO;
import io.metersphere.plan.dto.AssociationNode;
@ -30,4 +31,8 @@ public interface ExtTestPlanFunctionalCaseMapper {
List<ProjectOptionDTO> selectRootIdByTestPlanId(@Param("testPlanId") String testPlanId);
List<FunctionalCaseModuleDTO> selectBaseByProjectIdAndTestPlanId(@Param("testPlanId") String testPlanId);
List<FunctionalCaseModuleCountDTO> countModuleIdByRequest(@Param("request") TestPlanCaseRequest request, @Param("deleted") boolean deleted);
long caseCount(@Param("request") TestPlanCaseRequest request, @Param("deleted") boolean deleted);
}

View File

@ -94,6 +94,7 @@
LEFT JOIN project_version ON functional_case.version_id = project_version.id
left join test_plan_functional_case on functional_case.id = test_plan_functional_case.functional_case_id
where functional_case.deleted = #{deleted}
and test_plan_functional_case.test_plan_id = #{request.testPlanId}
and functional_case.project_id = #{request.projectId}
<include refid="queryWhereCondition"/>
order by
@ -392,4 +393,24 @@
(SELECT fc.module_id FROM functional_case fc LEFT JOIN test_plan_functional_case tpfc ON tpfc.functional_case_id = fc.id WHERE tpfc.test_plan_id = #{testPlanId} AND fc.deleted = false)
ORDER BY pos
</select>
<select id="countModuleIdByRequest" resultType="io.metersphere.functional.dto.FunctionalCaseModuleCountDTO">
SELECT functional_case.module_id AS moduleId, count(functional_case.id) AS dataCount, functional_case.project_id AS projectId, project.name AS projectName
FROM test_plan_functional_case tpfc
LEFT JOIN functional_case ON tpfc.functional_case_id = functional_case.id
LEFT JOIN project ON functional_case.project_id = project.id
WHERE tpfc.test_plan_id = #{request.testPlanId}
AND functional_case.deleted = #{deleted}
<include refid="queryWhereCondition"/>
GROUP BY module_id
</select>
<select id="caseCount"
resultType="java.lang.Long">
SELECT count(functional_case.id)
FROM test_plan_functional_case tpfc LEFT JOIN functional_case ON tpfc.functional_case_id = functional_case.id
WHERE tpfc.test_plan_id = #{request.testPlanId}
AND functional_case.deleted = #{deleted}
<include refid="queryWhereCondition"/>
</select>
</mapper>

View File

@ -31,4 +31,6 @@ public interface ExtTestPlanModuleMapper {
String selectProjectIdByModuleId(String id);
List<BaseTreeNode> selectBaseByIds(@Param("ids") List<String> ids);
List<String> selectIdByProjectIdAndTestPlanId(@Param("projectId") String projectId, @Param("testPlanId") String testPlanId);
}

View File

@ -83,4 +83,11 @@
</foreach>
ORDER BY pos
</select>
<select id="selectIdByProjectIdAndTestPlanId" resultType="java.lang.String">
SELECT tpm.id, tpm.project_id
FROM test_plan_module tpm
WHERE tpm.id IN
(SELECT fc.module_id FROM functional_case fc LEFT JOIN test_plan_functional_case tpfc ON tpfc.functional_case_id = fc.id WHERE tpfc.test_plan_id = #{testPlanId} AND fc.deleted = false and fc.project_id = #{projectId})
</select>
</mapper>

View File

@ -4,6 +4,7 @@ import io.metersphere.bug.dto.CaseRelateBugDTO;
import io.metersphere.bug.mapper.ExtBugRelateCaseMapper;
import io.metersphere.functional.domain.FunctionalCaseModule;
import io.metersphere.functional.dto.FunctionalCaseCustomFieldDTO;
import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO;
import io.metersphere.functional.dto.FunctionalCaseModuleDTO;
import io.metersphere.functional.dto.ProjectOptionDTO;
import io.metersphere.functional.service.FunctionalCaseService;
@ -19,11 +20,14 @@ import io.metersphere.plan.dto.response.TestPlanAssociationResponse;
import io.metersphere.plan.dto.response.TestPlanCasePageResponse;
import io.metersphere.plan.dto.response.TestPlanResourceSortResponse;
import io.metersphere.plan.mapper.ExtTestPlanFunctionalCaseMapper;
import io.metersphere.plan.mapper.ExtTestPlanModuleMapper;
import io.metersphere.plan.mapper.TestPlanFunctionalCaseMapper;
import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.project.domain.Project;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.sdk.constants.TestPlanResourceConstants;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.dto.LogInsertModule;
import io.metersphere.system.dto.sdk.BaseTreeNode;
@ -39,10 +43,7 @@ import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -69,6 +70,10 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
private TestPlanModuleService testPlanModuleService;
@Resource
private TestPlanCaseService testPlanCaseService;
@Resource
private ExtTestPlanModuleMapper extTestPlanModuleMapper;
private static final String CASE_MODULE_COUNT_ALL = "all";
@Override
public int deleteBatchByTestPlanId(List<String> testPlanIdList) {
@ -203,4 +208,51 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
});
return returnList;
}
public Map<String, Long> moduleCount(TestPlanCaseRequest request) {
//查出每个模块节点下的资源数量 不需要按照模块进行筛选
request.setModuleIds(null);
List<FunctionalCaseModuleCountDTO> projectModuleCountDTOList = extTestPlanFunctionalCaseMapper.countModuleIdByRequest(request, false);
Map<String, List<FunctionalCaseModuleCountDTO>> projectCountMap = projectModuleCountDTOList.stream().collect(Collectors.groupingBy(FunctionalCaseModuleCountDTO::getProjectId));
Map<String, Long> projectModuleCountMap = new HashMap<>();
projectCountMap.forEach((projectId, moduleCountDTOList) -> {
List<ModuleCountDTO> moduleCountDTOS = new ArrayList<>();
for (FunctionalCaseModuleCountDTO functionalCaseModuleCountDTO : moduleCountDTOList) {
ModuleCountDTO moduleCountDTO = new ModuleCountDTO();
BeanUtils.copyBean(moduleCountDTO, functionalCaseModuleCountDTO);
moduleCountDTOS.add(moduleCountDTO);
}
int sum = moduleCountDTOList.stream().mapToInt(FunctionalCaseModuleCountDTO::getDataCount).sum();
Map<String, Long> moduleCountMap = getModuleCountMap(projectId, request.getTestPlanId(), moduleCountDTOS);
moduleCountMap.forEach((k, v) -> {
if (projectModuleCountMap.get(k) == null || projectModuleCountMap.get(k) == 0L) {
projectModuleCountMap.put(k, v);
}
});
projectModuleCountMap.put(projectId, (long) sum);
});
//查出全部用例数量
long allCount = extTestPlanFunctionalCaseMapper.caseCount(request, false);
projectModuleCountMap.put(CASE_MODULE_COUNT_ALL, allCount);
return projectModuleCountMap;
}
public Map<String, Long> getModuleCountMap(String projectId, String testPlanId, List<ModuleCountDTO> moduleCountDTOList) {
//构建模块树并计算每个节点下的所有数量包含子节点
List<BaseTreeNode> treeNodeList = this.getTreeOnlyIdsAndResourceCount(projectId, testPlanId, moduleCountDTOList);
//通过广度遍历的方式构建返回值
return testPlanModuleService.getIdCountMapByBreadth(treeNodeList);
}
public List<BaseTreeNode> getTreeOnlyIdsAndResourceCount(String projectId, String testPlanId, List<ModuleCountDTO> moduleCountDTOList) {
//节点内容只有Id和parentId
List<String> moduleIds = extTestPlanModuleMapper.selectIdByProjectIdAndTestPlanId(projectId, testPlanId);
List<BaseTreeNode> nodeByNodeIds = testPlanModuleService.getNodeByNodeIds(moduleIds);
return testPlanModuleService.buildTreeAndCountResource(nodeByNodeIds, moduleCountDTOList, true, Translator.get("functional_case.module.default.name"));
}
}

View File

@ -21,6 +21,7 @@ public class TestPlanCaseControllerTests extends BaseTest {
public static final String FUNCTIONAL_CASE_LIST_URL = "/test-plan/functional/case/page";
public static final String FUNCTIONAL_CASE_TREE_URL = "/test-plan/functional/case/tree/";
public static final String FUNCTIONAL_CASE_TREE_COUNT_URL = "/test-plan/functional/case/module/count";
@Test
@Order(1)
@ -30,6 +31,7 @@ public class TestPlanCaseControllerTests extends BaseTest {
request.setProjectId("123");
request.setCurrent(1);
request.setPageSize(10);
request.setTestPlanId("plan_1");
this.requestPost(FUNCTIONAL_CASE_LIST_URL, request);
request.setSort(new HashMap<>() {{
put("createTime", "desc");
@ -51,4 +53,20 @@ public class TestPlanCaseControllerTests extends BaseTest {
this.requestGetWithOkAndReturn(FUNCTIONAL_CASE_TREE_URL + "plan_2");
}
@Test
@Order(3)
public void testGetFunctionalCaseTreeCount() throws Exception {
TestPlanCaseRequest request = new TestPlanCaseRequest();
request.setProjectId("123");
request.setCurrent(1);
request.setPageSize(10);
request.setTestPlanId("plan_1");
MvcResult mvcResult = this.requestPostWithOkAndReturn(FUNCTIONAL_CASE_TREE_COUNT_URL, request);
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
Assertions.assertNotNull(resultHolder);
}
}