feat(测试跟踪): 测试跟踪模块后显示该模块下的用例数,接口定义模块显示模块下的接口数,接口自动化模块显示模块下的场景数

This commit is contained in:
wenyann 2021-05-24 11:55:30 +08:00 committed by 刘瑞斌
parent 9afb9c9300
commit 57dd5d03b8
10 changed files with 182 additions and 31 deletions

View File

@ -2,10 +2,7 @@ package io.metersphere.api.service;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.definition.ApiDefinitionRequest;
import io.metersphere.api.dto.definition.ApiDefinitionResult;
import io.metersphere.api.dto.definition.ApiModuleDTO;
import io.metersphere.api.dto.definition.DragModuleRequest;
import io.metersphere.api.dto.definition.*;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiDefinitionMapper;
import io.metersphere.base.mapper.ApiModuleMapper;
@ -21,6 +18,8 @@ import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.log.vo.api.ModuleReference;
import io.metersphere.service.NodeTreeService;
import io.metersphere.service.ProjectService;
import io.metersphere.track.dto.TestCaseNodeDTO;
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
import io.metersphere.track.service.TestPlanApiCaseService;
import io.metersphere.track.service.TestPlanProjectService;
import org.apache.commons.collections.CollectionUtils;
@ -81,9 +80,43 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> {
apiModuleMapper.insert(record);
}
List<ApiModuleDTO> apiModules = extApiModuleMapper.getNodeTreeByProjectId(projectId, protocol);
ApiDefinitionRequest request = new ApiDefinitionRequest();
request.setProjectId(projectId);
request.setProtocol(protocol);
List<String> list = new ArrayList<>();
list.add("Prepare");
list.add("Underway");
list.add("Completed");
Map<String, List<String>> filters = new LinkedHashMap<>();
filters.put("status", list);
request.setFilters(filters);
apiModules.forEach(node -> {
List<String> moduleIds = new ArrayList<>();
moduleIds = this.nodeList(apiModules, node.getId(), moduleIds);
moduleIds.add(node.getId());
request.setModuleIds(moduleIds);
int num = this.getCaseNum(request);
node.setCaseNum(num);
});
return getNodeTrees(apiModules);
}
private int getCaseNum(ApiDefinitionRequest request) {
return extApiDefinitionMapper.list(request).size();
}
public static List<String> nodeList(List<ApiModuleDTO> apiNodes, String pid, List<String> list) {
for (ApiModuleDTO node : apiNodes) {
//遍历出父id等于参数的idadd进子节点集合
if (StringUtils.equals(node.getParentId(), pid)) {
list.add(node.getId());
//递归遍历下一级
nodeList(apiNodes, node.getId(), list);
}
}
return list;
}
public String addNode(ApiModule node) {
validateNode(node);
return addNodeWithoutValidate(node);

View File

@ -9,6 +9,7 @@ import io.metersphere.api.dto.automation.DragApiScenarioModuleRequest;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiScenarioModuleMapper;
import io.metersphere.base.mapper.ext.ExtApiScenarioMapper;
import io.metersphere.base.mapper.ext.ExtApiScenarioModuleMapper;
import io.metersphere.commons.constants.TestCaseConstants;
import io.metersphere.commons.exception.MSException;
@ -20,6 +21,8 @@ import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.log.vo.api.ModuleReference;
import io.metersphere.service.NodeTreeService;
import io.metersphere.service.ProjectService;
import io.metersphere.track.dto.TestCaseNodeDTO;
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
import io.metersphere.track.service.TestPlanProjectService;
import io.metersphere.track.service.TestPlanScenarioCaseService;
import org.apache.commons.lang3.StringUtils;
@ -52,6 +55,8 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD
TestPlanProjectService testPlanProjectService;
@Resource
private ProjectService projectService;
@Resource
private ExtApiScenarioMapper extApiScenarioMapper;
public ApiScenarioModuleService() {
super(ApiScenarioModuleDTO.class);
@ -75,9 +80,43 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD
}
List<ApiScenarioModuleDTO> nodes = extApiScenarioModuleMapper.getNodeTreeByProjectId(projectId);
ApiScenarioRequest request = new ApiScenarioRequest();
request.setProjectId(projectId);
List<String> list = new ArrayList<>();
list.add("Prepare");
list.add("Underway");
list.add("Completed");
Map<String, List<String>> filters = new LinkedHashMap<>();
filters.put("status", list);
request.setFilters(filters);
nodes.forEach(node -> {
List<String> scenarioNodes = new ArrayList<>();
scenarioNodes = this.nodeList(nodes, node.getId(), scenarioNodes);
scenarioNodes.add(node.getId());
request.setModuleIds(scenarioNodes);
int num = this.getCaseNum(request);
node.setCaseNum(num);
});
return getNodeTrees(nodes);
}
private int getCaseNum(ApiScenarioRequest request) {
return extApiScenarioMapper.list(request).size();
}
public static List<String> nodeList(List<ApiScenarioModuleDTO> nodes, String pid, List<String> list) {
for (ApiScenarioModuleDTO node : nodes) {
//遍历出父id等于参数的idadd进子节点集合
if (StringUtils.equals(node.getParentId(), pid)) {
list.add(node.getId());
//递归遍历下一级
nodeList(nodes, node.getId(), list);
}
}
return list;
}
private double getNextLevelPos(String projectId, int level, String parentId) {
List<ApiScenarioModule> list = getPos(projectId, level, parentId, "pos desc");
if (!CollectionUtils.isEmpty(list) && list.get(0) != null && list.get(0).getPos() != null) {

View File

@ -14,4 +14,6 @@ public interface ExtTestCaseNodeMapper {
TestCaseNodeDTO get(String id);
void updatePos(String id, Double pos);
List<String> getNodes(@Param("parentId") String parentId);
}

View File

@ -24,8 +24,14 @@
from test_case_node
where id = #{id}
</select>
<select id="getNodes" resultType="java.lang.String">
select id
from test_case_node
where parent_id = #{parentId}
</select>
<update id="updatePos">
update test_case_node set pos = #{pos}
update test_case_node
set pos = #{pos}
where id = #{id}
</update>
</mapper>

View File

@ -0,0 +1,9 @@
package io.metersphere.dto;
import io.metersphere.base.domain.TestCaseNode;
import lombok.Data;
@Data
public class NodeNumDTO extends TestCaseNode {
private Integer caseNum;
}

View File

@ -27,5 +27,7 @@ public class TreeNodeDTO<T> {
private List<T> children;
private Integer caseNum;
private static final long serialVersionUID = 1L;
}

View File

@ -11,6 +11,7 @@ import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper;
import io.metersphere.commons.constants.TestCaseConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.dto.NodeNumDTO;
import io.metersphere.exception.ExcelException;
import io.metersphere.i18n.Translator;
import io.metersphere.log.utils.ReflexObjectUtil;
@ -29,6 +30,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@ -84,6 +86,12 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
return node.getId();
}
public List<String> getNodes(String nodeId) {
return extTestCaseNodeMapper.getNodes(nodeId);
}
;
private void validateNode(TestCaseNode node) {
if (node.getLevel() > TestCaseConstants.MAX_NODE_DEPTH) {
throw new RuntimeException(Translator.get("test_case_node_level_tip")
@ -118,7 +126,8 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
example.createCriteria().andProjectIdEqualTo(projectId).andNameEqualTo("默认模块");
long count = testCaseNodeMapper.countByExample(example);
if (count <= 0) {
TestCaseNode record = new TestCaseNode();
NodeNumDTO record = new NodeNumDTO();
//TestCaseNode record = new TestCaseNode();
record.setId(UUID.randomUUID().toString());
record.setCreateUser(SessionUtils.getUserId());
record.setName("默认模块");
@ -128,11 +137,45 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
record.setUpdateTime(System.currentTimeMillis());
record.setProjectId(projectId);
testCaseNodeMapper.insert(record);
record.setCaseNum(0);
}
List<TestCaseNodeDTO> testCaseNodes = extTestCaseNodeMapper.getNodeTreeByProjectId(projectId);
QueryTestCaseRequest request = new QueryTestCaseRequest();
request.setUserId(SessionUtils.getUserId());
request.setProjectId(projectId);
for (TestCaseNodeDTO node : testCaseNodes) {
List<String> nodeIds = new ArrayList<>();
nodeIds = this.nodeList(testCaseNodes, node.getId(), nodeIds);
nodeIds.add(node.getId());
request.setNodeIds(nodeIds);
int num = this.getCaseNum(request);
node.setCaseNum(num);
}
return getNodeTrees(testCaseNodes);
}
public static List<String> nodeList(List<TestCaseNodeDTO> testCaseNodes, String pid, List<String> list) {
for (TestCaseNodeDTO node : testCaseNodes) {
//遍历出父id等于参数的idadd进子节点集合
if (StringUtils.equals(node.getParentId(), pid)) {
list.add(node.getId());
//递归遍历下一级
nodeList(testCaseNodes, node.getId(), list);
}
}
/*if(null==list||list.size()==0){
list.add(pid);
}*/
return list;
}
//获取模块下用例数
public int getCaseNum(QueryTestCaseRequest request) {
List<TestCaseDTO> list = extTestCaseMapper.list(request);
return list.size();
}
public int editNode(DragNodeRequest request) {
request.setUpdateTime(System.currentTimeMillis());
checkTestCaseNodeExist(request);

View File

@ -299,6 +299,7 @@ export default {
if ( this.$refs.testCaseList) {
this.$refs.testCaseList.initTableData();
}
this.$refs.nodeTree.list();
},
editTestCase(testCase) {
this.type = "edit";

View File

@ -22,22 +22,25 @@
<span class="custom-tree-node father" @click="handleNodeSelect(node)">
<span v-if="data.isEdit" @click.stop>
<el-input @blur.stop="save(node, data)" @keyup.enter.native.stop="$event.target.blur" v-model="data.name" class="name-input" size="mini" ref="nameInput"/>
<el-input @blur.stop="save(node, data)" @keyup.enter.native.stop="$event.target.blur" v-model="data.name"
class="name-input" size="mini" ref="nameInput"/>
</span>
<span v-if="!data.isEdit" class="node-icon">
<i class="el-icon-folder"/>
</span>
<span v-if="!data.isEdit" class="node-title" v-text="data.name"/>
<span v-if="data.caseNum" class="node-title">
<span>(0/{{ data.caseNum }})</span>
</span>
<span v-if="!disabled" class="node-operate child">
<el-tooltip
v-if="data.id !== 'root' && data.name !=='默认模块'"
class="item"
effect="dark"
:open-delay="200"
:content="$t('test_track.module.rename')"
placement="top">
v-if="data.id !== 'root' && data.name !=='默认模块'"
class="item"
effect="dark"
:open-delay="200"
:content="$t('test_track.module.rename')"
placement="top">
<i @click.stop="edit(node, data)" class="el-icon-edit"></i>
</el-tooltip>
<el-tooltip

View File

@ -5,11 +5,11 @@
<project-change :project-name="currentProject"/>
<el-col :span="14">
<el-menu class="header-menu" :unique-opened="true" mode="horizontal" router
:default-active='$route.path'>
:default-active="pathName">
<el-menu-item :index="'/track/home'">
{{ $t("i18n.home") }}
</el-menu-item>
<el-menu-item :index="'/track/case/all'">
<el-menu-item :index="'/track/case/all'" v-permission="['test_manager','test_user','test_viewer']">
{{ $t("test_track.case.test_case") }}
</el-menu-item>
<!--
@ -25,10 +25,12 @@
:title="$t('test_track.case.create_case')"/>
</el-submenu>
-->
<el-menu-item :index="'/track/review/all'">
<el-menu-item :index="'/track/review/all'" v-permission="['test_manager','test_user','test_viewer']"
popper-class="submenu">
{{ $t('test_track.review.test_review') }}
</el-menu-item>
<el-menu-item :index="'/track/plan/all'">
<el-menu-item :index="'/track/plan/all'" v-permission="['test_manager','test_user','test_viewer']"
popper-class="submenu">
{{ $t('test_track.plan.test_plan') }}
</el-menu-item>
@ -40,18 +42,18 @@
<ms-show-all :index="'/track/review/all'"/>
<el-menu-item :index="testCaseReviewEditPath" class="blank_item"/>
<ms-create-button v-permission="['test_manager','test_user']" :index="'/track/review/create'" :title="$t('test_track.review.create_review')"/>-->
<!-- </el-submenu>
<el-submenu v-permission="['test_manager','test_user','test_viewer']" :index="'/track/plan/all'" popper-class="submenu">-->
<!-- <template v-slot:title>{{ $t('test_track.plan.test_plan') }}</template>
<ms-recent-list ref="planRecent" :options="planRecent"/>
<el-divider/>
<ms-show-all :index="'/track/plan/all'"/>
<el-menu-item :index="testPlanViewPath" class="blank_item"></el-menu-item>
<ms-create-button v-permission="['test_manager','test_user']" :index="'/track/plan/create'"
:title="$t('test_track.plan.create_plan')"/>-->
<!-- </el-submenu>-->
<!-- <el-submenu v-permission="['test_manager','test_user','test_viewer']" :index="'/track/plan/all'" popper-class="submenu">
<template v-slot:title>{{ $t('test_track.plan.test_plan') }}</template>
<ms-recent-list ref="planRecent" :options="planRecent"/>
<el-divider/>
<ms-show-all :index="'/track/plan/all'"/>
<el-menu-item :index="testPlanViewPath" class="blank_item"></el-menu-item>
<ms-create-button v-permission="['test_manager','test_user']" :index="'/track/plan/create'"
:title="$t('test_track.plan.create_plan')"/>
</el-submenu>-->
<el-menu-item :index="'/track/issue'">
{{ $t("缺陷管理") }}
</el-menu-item>
@ -113,12 +115,23 @@ export default {
},
router: function (item) {
}
}
},
pathName: '',
}
},
watch: {
'$route'(to) {
this.init();
'$route': {
immediate: true,
handler(to, from) {
if (to.params && to.params.reviewId) {
this.pathName = '/track/review/all';
} else if (to.params && to.params.planId) {
this.pathName = '/track/plan/all';
} else {
this.pathName = to.path;
}
this.init();
}
}
},
mounted() {