feat(测试计划): 已关联用例模块树统计
This commit is contained in:
parent
2b8486732d
commit
5cf923b55c
|
@ -1,7 +1,9 @@
|
||||||
package io.metersphere.plan.controller;
|
package io.metersphere.plan.controller;
|
||||||
|
|
||||||
|
import com.alibaba.excel.util.StringUtils;
|
||||||
import com.github.pagehelper.Page;
|
import com.github.pagehelper.Page;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
|
import io.metersphere.functional.request.ReviewFunctionalCasePageRequest;
|
||||||
import io.metersphere.plan.constants.TestPlanResourceConfig;
|
import io.metersphere.plan.constants.TestPlanResourceConfig;
|
||||||
import io.metersphere.plan.dto.request.ResourceSortRequest;
|
import io.metersphere.plan.dto.request.ResourceSortRequest;
|
||||||
import io.metersphere.plan.dto.request.TestPlanAssociationRequest;
|
import io.metersphere.plan.dto.request.TestPlanAssociationRequest;
|
||||||
|
@ -28,6 +30,7 @@ import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@Tag(name = "测试计划功能用例")
|
@Tag(name = "测试计划功能用例")
|
||||||
|
@ -61,7 +64,7 @@ public class TestPlanFunctionalCaseController {
|
||||||
@PostMapping("/page")
|
@PostMapping("/page")
|
||||||
@Operation(summary = "测试计划-已关联功能用例分页查询")
|
@Operation(summary = "测试计划-已关联功能用例分页查询")
|
||||||
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ)
|
@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) {
|
public Pager<List<TestPlanCasePageResponse>> page(@Validated @RequestBody TestPlanCaseRequest request) {
|
||||||
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize());
|
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize());
|
||||||
return PageUtils.setPageInfo(page, testPlanFunctionalCaseService.getFunctionalCasePage(request, false));
|
return PageUtils.setPageInfo(page, testPlanFunctionalCaseService.getFunctionalCasePage(request, false));
|
||||||
|
@ -76,4 +79,11 @@ public class TestPlanFunctionalCaseController {
|
||||||
return testPlanFunctionalCaseService.getTree(testPlanId);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,10 @@ public class TestPlanCaseRequest extends BasePageRequest implements Serializable
|
||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
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)
|
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
@NotBlank(message = "{functional_case.project_id.not_blank}")
|
@NotBlank(message = "{functional_case.project_id.not_blank}")
|
||||||
private String projectId;
|
private String projectId;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package io.metersphere.plan.mapper;
|
package io.metersphere.plan.mapper;
|
||||||
|
|
||||||
|
import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO;
|
||||||
import io.metersphere.functional.dto.FunctionalCaseModuleDTO;
|
import io.metersphere.functional.dto.FunctionalCaseModuleDTO;
|
||||||
import io.metersphere.functional.dto.ProjectOptionDTO;
|
import io.metersphere.functional.dto.ProjectOptionDTO;
|
||||||
import io.metersphere.plan.dto.AssociationNode;
|
import io.metersphere.plan.dto.AssociationNode;
|
||||||
|
@ -30,4 +31,8 @@ public interface ExtTestPlanFunctionalCaseMapper {
|
||||||
List<ProjectOptionDTO> selectRootIdByTestPlanId(@Param("testPlanId") String testPlanId);
|
List<ProjectOptionDTO> selectRootIdByTestPlanId(@Param("testPlanId") String testPlanId);
|
||||||
|
|
||||||
List<FunctionalCaseModuleDTO> selectBaseByProjectIdAndTestPlanId(@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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,6 +94,7 @@
|
||||||
LEFT JOIN project_version ON functional_case.version_id = project_version.id
|
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
|
left join test_plan_functional_case on functional_case.id = test_plan_functional_case.functional_case_id
|
||||||
where functional_case.deleted = #{deleted}
|
where functional_case.deleted = #{deleted}
|
||||||
|
and test_plan_functional_case.test_plan_id = #{request.testPlanId}
|
||||||
and functional_case.project_id = #{request.projectId}
|
and functional_case.project_id = #{request.projectId}
|
||||||
<include refid="queryWhereCondition"/>
|
<include refid="queryWhereCondition"/>
|
||||||
order by
|
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)
|
(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
|
ORDER BY pos
|
||||||
</select>
|
</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>
|
</mapper>
|
|
@ -31,4 +31,6 @@ public interface ExtTestPlanModuleMapper {
|
||||||
String selectProjectIdByModuleId(String id);
|
String selectProjectIdByModuleId(String id);
|
||||||
|
|
||||||
List<BaseTreeNode> selectBaseByIds(@Param("ids") List<String> ids);
|
List<BaseTreeNode> selectBaseByIds(@Param("ids") List<String> ids);
|
||||||
|
|
||||||
|
List<String> selectIdByProjectIdAndTestPlanId(@Param("projectId") String projectId, @Param("testPlanId") String testPlanId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,4 +83,11 @@
|
||||||
</foreach>
|
</foreach>
|
||||||
ORDER BY pos
|
ORDER BY pos
|
||||||
</select>
|
</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>
|
</mapper>
|
|
@ -4,6 +4,7 @@ import io.metersphere.bug.dto.CaseRelateBugDTO;
|
||||||
import io.metersphere.bug.mapper.ExtBugRelateCaseMapper;
|
import io.metersphere.bug.mapper.ExtBugRelateCaseMapper;
|
||||||
import io.metersphere.functional.domain.FunctionalCaseModule;
|
import io.metersphere.functional.domain.FunctionalCaseModule;
|
||||||
import io.metersphere.functional.dto.FunctionalCaseCustomFieldDTO;
|
import io.metersphere.functional.dto.FunctionalCaseCustomFieldDTO;
|
||||||
|
import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO;
|
||||||
import io.metersphere.functional.dto.FunctionalCaseModuleDTO;
|
import io.metersphere.functional.dto.FunctionalCaseModuleDTO;
|
||||||
import io.metersphere.functional.dto.ProjectOptionDTO;
|
import io.metersphere.functional.dto.ProjectOptionDTO;
|
||||||
import io.metersphere.functional.service.FunctionalCaseService;
|
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.TestPlanCasePageResponse;
|
||||||
import io.metersphere.plan.dto.response.TestPlanResourceSortResponse;
|
import io.metersphere.plan.dto.response.TestPlanResourceSortResponse;
|
||||||
import io.metersphere.plan.mapper.ExtTestPlanFunctionalCaseMapper;
|
import io.metersphere.plan.mapper.ExtTestPlanFunctionalCaseMapper;
|
||||||
|
import io.metersphere.plan.mapper.ExtTestPlanModuleMapper;
|
||||||
import io.metersphere.plan.mapper.TestPlanFunctionalCaseMapper;
|
import io.metersphere.plan.mapper.TestPlanFunctionalCaseMapper;
|
||||||
import io.metersphere.plan.mapper.TestPlanMapper;
|
import io.metersphere.plan.mapper.TestPlanMapper;
|
||||||
import io.metersphere.project.domain.Project;
|
import io.metersphere.project.domain.Project;
|
||||||
|
import io.metersphere.project.dto.ModuleCountDTO;
|
||||||
import io.metersphere.sdk.constants.TestPlanResourceConstants;
|
import io.metersphere.sdk.constants.TestPlanResourceConstants;
|
||||||
import io.metersphere.sdk.exception.MSException;
|
import io.metersphere.sdk.exception.MSException;
|
||||||
|
import io.metersphere.sdk.util.BeanUtils;
|
||||||
import io.metersphere.sdk.util.Translator;
|
import io.metersphere.sdk.util.Translator;
|
||||||
import io.metersphere.system.dto.LogInsertModule;
|
import io.metersphere.system.dto.LogInsertModule;
|
||||||
import io.metersphere.system.dto.sdk.BaseTreeNode;
|
import io.metersphere.system.dto.sdk.BaseTreeNode;
|
||||||
|
@ -39,10 +43,7 @@ import org.mybatis.spring.SqlSessionUtils;
|
||||||
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.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ -69,6 +70,10 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
|
||||||
private TestPlanModuleService testPlanModuleService;
|
private TestPlanModuleService testPlanModuleService;
|
||||||
@Resource
|
@Resource
|
||||||
private TestPlanCaseService testPlanCaseService;
|
private TestPlanCaseService testPlanCaseService;
|
||||||
|
@Resource
|
||||||
|
private ExtTestPlanModuleMapper extTestPlanModuleMapper;
|
||||||
|
|
||||||
|
private static final String CASE_MODULE_COUNT_ALL = "all";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int deleteBatchByTestPlanId(List<String> testPlanIdList) {
|
public int deleteBatchByTestPlanId(List<String> testPlanIdList) {
|
||||||
|
@ -203,4 +208,51 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
|
||||||
});
|
});
|
||||||
return returnList;
|
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"));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_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_URL = "/test-plan/functional/case/tree/";
|
||||||
|
public static final String FUNCTIONAL_CASE_TREE_COUNT_URL = "/test-plan/functional/case/module/count";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(1)
|
@Order(1)
|
||||||
|
@ -30,6 +31,7 @@ public class TestPlanCaseControllerTests extends BaseTest {
|
||||||
request.setProjectId("123");
|
request.setProjectId("123");
|
||||||
request.setCurrent(1);
|
request.setCurrent(1);
|
||||||
request.setPageSize(10);
|
request.setPageSize(10);
|
||||||
|
request.setTestPlanId("plan_1");
|
||||||
this.requestPost(FUNCTIONAL_CASE_LIST_URL, request);
|
this.requestPost(FUNCTIONAL_CASE_LIST_URL, request);
|
||||||
request.setSort(new HashMap<>() {{
|
request.setSort(new HashMap<>() {{
|
||||||
put("createTime", "desc");
|
put("createTime", "desc");
|
||||||
|
@ -51,4 +53,20 @@ public class TestPlanCaseControllerTests extends BaseTest {
|
||||||
|
|
||||||
this.requestGetWithOkAndReturn(FUNCTIONAL_CASE_TREE_URL + "plan_2");
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue