获取测试报告数据

This commit is contained in:
chenjianxing 2020-05-08 14:06:33 +08:00
parent 2a3b1a2036
commit cff0b05b32
14 changed files with 187 additions and 94 deletions

View File

@ -1,18 +1,13 @@
package io.metersphere.base.mapper.ext; package io.metersphere.base.mapper.ext;
import io.metersphere.base.domain.TestCase; import io.metersphere.dto.TestCaseReportStatusResultDTO;
import io.metersphere.controller.request.testcase.QueryTestCaseRequest;
import io.metersphere.controller.request.testplancase.QueryTestPlanCaseRequest;
import io.metersphere.dto.TestCaseReportMetricDTO;
import io.metersphere.dto.TestCaseReportResultDTO;
import io.metersphere.dto.TestPlanCaseDTO;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
public interface ExtTestPlanTestCaseMapper { public interface ExtTestPlanTestCaseMapper {
List<TestCaseReportResultDTO> getReportMetric(@Param("planId") String planId); List<TestCaseReportStatusResultDTO> getReportMetric(@Param("planId") String planId);
List<String> getExecutors(@Param("planId") String planId); List<String> getExecutors(@Param("planId") String planId);
} }

View File

@ -2,7 +2,7 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper"> <mapper namespace="io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper">
<select id="getReportMetric" parameterType="java.lang.String" resultType="io.metersphere.dto.TestCaseReportResultDTO"> <select id="getReportMetric" parameterType="java.lang.String" resultType="io.metersphere.dto.TestCaseReportStatusResultDTO">
select count(t1.id) as `count`, t1.status select count(t1.id) as `count`, t1.status
from test_plan_test_case t1 from test_plan_test_case t1
inner join test_case t2 inner join test_case t2

View File

@ -2,6 +2,7 @@ package io.metersphere.controller;
import io.metersphere.base.domain.TestCaseReport; import io.metersphere.base.domain.TestCaseReport;
import io.metersphere.controller.request.testCaseReport.CreateReportRequest; import io.metersphere.controller.request.testCaseReport.CreateReportRequest;
import io.metersphere.dto.TestCaseReportMetricDTO;
import io.metersphere.service.TestCaseReportService; import io.metersphere.service.TestCaseReportService;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -41,7 +42,7 @@ public class TestCaseReportController {
} }
@GetMapping("/get/metric/{planId}") @GetMapping("/get/metric/{planId}")
public TestCaseReport getMetric(@PathVariable String planId){ public TestCaseReportMetricDTO getMetric(@PathVariable String planId){
return testCaseReportService.getMetric(planId); return testCaseReportService.getMetric(planId);
} }
} }

View File

@ -7,7 +7,7 @@ import java.util.List;
@Data @Data
public class TestCaseReportMetricDTO { public class TestCaseReportMetricDTO {
private List<TestCaseReportResultDTO> executeResult; private List<TestCaseReportStatusResultDTO> executeResult;
private List<TestCaseReportModuleResultDTO> moduleExecuteResult; private List<TestCaseReportModuleResultDTO> moduleExecuteResult;
private List<String> executors; private List<String> executors;
private String principal; private String principal;

View File

@ -4,8 +4,10 @@ import lombok.Data;
@Data @Data
public class TestCaseReportModuleResultDTO { public class TestCaseReportModuleResultDTO {
private String module; private String moduleId;
private String moduleName;
private Integer caseCount; private Integer caseCount;
private Integer passRate; private Integer passCount;
private Double passRate;
private Integer flawCount; private Integer flawCount;
} }

View File

@ -1,9 +1,9 @@
package io.metersphere.dto; package io.metersphere.dto;
import lombok.Data; import lombok.Data;
@Data @Data
public class TestCaseReportResultDTO { public class TestCaseReportStatusResultDTO {
private String status; private String status;
private String count; private Integer count;
} }

View File

@ -51,7 +51,7 @@ public class TestCaseNodeService {
return getNodeTrees(nodes); return getNodeTrees(nodes);
} }
private List<TestCaseNodeDTO> getNodeTrees(List<TestCaseNode> nodes) { public List<TestCaseNodeDTO> getNodeTrees(List<TestCaseNode> nodes) {
List<TestCaseNodeDTO> nodeTreeList = new ArrayList<>(); List<TestCaseNodeDTO> nodeTreeList = new ArrayList<>();
@ -91,12 +91,12 @@ public class TestCaseNodeService {
return nodeTree; return nodeTree;
} }
List<TestCaseNodeDTO> childrens = Optional.ofNullable(nodeTree.getChildren()).orElse(new ArrayList<>()); List<TestCaseNodeDTO> children = Optional.ofNullable(nodeTree.getChildren()).orElse(new ArrayList<>());
lowerNodes.forEach(node -> { lowerNodes.forEach(node -> {
if (node.getParentId() != null && node.getParentId().equals(rootNode.getId())){ if (node.getParentId() != null && node.getParentId().equals(rootNode.getId())){
childrens.add(buildNodeTree(nodeLevelMap, node)); children.add(buildNodeTree(nodeLevelMap, node));
nodeTree.setChildren(childrens); nodeTree.setChildren(children);
} }
}); });

View File

@ -2,20 +2,21 @@ package io.metersphere.service;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*; import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanMapper; import io.metersphere.base.mapper.ext.ExtTestPlanMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper; import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper;
import io.metersphere.commons.constants.TestPlanTestCaseStatus;
import io.metersphere.commons.utils.BeanUtils; import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.controller.request.testCaseReport.CreateReportRequest; import io.metersphere.controller.request.testCaseReport.CreateReportRequest;
import io.metersphere.controller.request.testcase.QueryTestPlanRequest; import io.metersphere.controller.request.testcase.QueryTestPlanRequest;
import io.metersphere.dto.TestCaseNodeDTO; import io.metersphere.controller.request.testplancase.QueryTestPlanCaseRequest;
import io.metersphere.dto.TestCaseReportMetricDTO; import io.metersphere.dto.*;
import io.metersphere.dto.TestCaseReportResultDTO;
import io.metersphere.dto.TestPlanDTO;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*; import java.util.*;
@Service @Service
@ -46,6 +47,9 @@ public class TestCaseReportService {
@Resource @Resource
TestPlanTestCaseMapper testPlanTestCaseMapper; TestPlanTestCaseMapper testPlanTestCaseMapper;
@Resource
ExtTestCaseMapper extTestCaseMapper;
public List<TestCaseReport> listTestCaseReport(TestCaseReport request) { public List<TestCaseReport> listTestCaseReport(TestCaseReport request) {
TestCaseReportExample example = new TestCaseReportExample(); TestCaseReportExample example = new TestCaseReportExample();
if ( StringUtils.isNotBlank(request.getName()) ) { if ( StringUtils.isNotBlank(request.getName()) ) {
@ -84,41 +88,110 @@ public class TestCaseReportService {
return report.getId(); return report.getId();
} }
public TestCaseReport getMetric(String planId) { public TestCaseReportMetricDTO getMetric(String planId) {
TestCaseReportMetricDTO testCaseReportMetricDTO = new TestCaseReportMetricDTO();
testCaseReportMetricDTO.setExecutors(extTestPlanTestCaseMapper.getExecutors(planId));
testCaseReportMetricDTO.setExecuteResult(extTestPlanTestCaseMapper.getReportMetric(planId));
QueryTestPlanRequest queryTestPlanRequest = new QueryTestPlanRequest(); QueryTestPlanRequest queryTestPlanRequest = new QueryTestPlanRequest();
queryTestPlanRequest.setId(planId); queryTestPlanRequest.setId(planId);
TestPlanDTO testPlan = extTestPlanMapper.list(queryTestPlanRequest).get(0); TestPlanDTO testPlan = extTestPlanMapper.list(queryTestPlanRequest).get(0);
testCaseReportMetricDTO.setProjectName(testPlan.getProjectName());
testCaseReportMetricDTO.setPrincipal(testPlan.getPrincipal());
TestPlanTestCaseExample example = new TestPlanTestCaseExample(); Set<String> executors = new HashSet<>();
example.createCriteria().andPlanIdEqualTo(planId); Map<String, TestCaseReportStatusResultDTO> reportStatusResultMap = new HashMap<>();
List<TestPlanTestCase> testPlanTestCases = testPlanTestCaseMapper.selectByExample(example);
TestCaseNodeExample testCaseNodeExample = new TestCaseNodeExample(); TestCaseNodeExample testCaseNodeExample = new TestCaseNodeExample();
testCaseNodeExample.createCriteria().andProjectIdEqualTo(testPlan.getProjectId()); testCaseNodeExample.createCriteria().andProjectIdEqualTo(testPlan.getProjectId());
List<TestCaseNode> nodes = testCaseNodeMapper.selectByExample(testCaseNodeExample); List<TestCaseNode> nodes = testCaseNodeMapper.selectByExample(testCaseNodeExample);
return null; List<TestCaseNodeDTO> nodeTrees = testCaseNodeService.getNodeTrees(nodes);
Map<String, Set<String>> childIdMap = new HashMap<>();
nodeTrees.forEach(item -> {
Set<String> childIds = new HashSet<>();
getChildIds(item, childIds);
childIdMap.put(item.getId(), childIds);
});
QueryTestPlanCaseRequest request = new QueryTestPlanCaseRequest();
request.setPlanId(planId);
List<TestPlanCaseDTO> testPlanTestCases = extTestCaseMapper.getTestPlanTestCases(request);
Map<String, TestCaseReportModuleResultDTO> moduleResultMap = new HashMap<>();
for (TestPlanCaseDTO testCase: testPlanTestCases) {
executors.add(testCase.getExecutor());
getStatusResultMap(reportStatusResultMap, testCase);
getModuleResultMap(childIdMap, moduleResultMap, testCase, nodeTrees);
}
nodeTrees.forEach(rootNode -> {
TestCaseReportModuleResultDTO moduleResult = moduleResultMap.get(rootNode.getId());
if (moduleResult != null) {
moduleResult.setModuleName(rootNode.getName());
}
});
for (TestCaseReportModuleResultDTO moduleResult : moduleResultMap.values()) {
moduleResult.setPassRate(new BigDecimal(moduleResult.getPassCount()*1.0f/moduleResult.getCaseCount())
.setScale(2, BigDecimal.ROUND_HALF_UP)
.doubleValue() * 100);
if (moduleResult.getCaseCount() <= 0) {
moduleResultMap.remove(moduleResult.getModuleId());
}
}
TestCaseReportMetricDTO testCaseReportMetricDTO = new TestCaseReportMetricDTO();
testCaseReportMetricDTO.setProjectName(testPlan.getProjectName());
testCaseReportMetricDTO.setPrincipal(testPlan.getPrincipal());
testCaseReportMetricDTO.setExecutors(new ArrayList<>(executors));
testCaseReportMetricDTO.setExecuteResult(new ArrayList<>(reportStatusResultMap.values()));
testCaseReportMetricDTO.setModuleExecuteResult(new ArrayList<>(moduleResultMap.values()));
return testCaseReportMetricDTO;
} }
private TestCaseReport get(List<TestCaseNode> nodes) { private void getStatusResultMap(Map<String, TestCaseReportStatusResultDTO> reportStatusResultMap, TestPlanCaseDTO testCase) {
TestCaseReportStatusResultDTO statusResult = reportStatusResultMap.get(testCase.getStatus());
// List<TestCaseNode> rootNode = new ArrayList<>(); if (statusResult == null) {
// Map<String, List<String>> nodeMap = new HashMap<>(); statusResult = new TestCaseReportStatusResultDTO();
// nodes.forEach(node -> { statusResult.setStatus(testCase.getStatus());
// Integer level = node.getLevel(); statusResult.setCount(0);
// if (level == 1) { }
// rootNode.add(node); statusResult.setCount(statusResult.getCount() + 1);
// ArrayList<Object> objects = new ArrayList<>(); reportStatusResultMap.put(testCase.getStatus(), statusResult);
// }
// });
return null;
} }
private void getModuleResultMap(Map<String, Set<String>> childIdMap, Map<String, TestCaseReportModuleResultDTO> moduleResultMap, TestPlanCaseDTO testCase, List<TestCaseNodeDTO> nodeTrees) {
childIdMap.forEach((rootNodeId, childIds) -> {
if (childIds.contains(testCase.getNodeId())) {
TestCaseReportModuleResultDTO moduleResult = moduleResultMap.get(rootNodeId);
if (moduleResult == null) {
moduleResult = new TestCaseReportModuleResultDTO();
moduleResult.setCaseCount(0);
moduleResult.setPassCount(0);
moduleResult.setModuleId(rootNodeId);
}
moduleResult.setCaseCount(moduleResult.getCaseCount() + 1);
if (StringUtils.equals(testCase.getStatus(), TestPlanTestCaseStatus.Pass.name())) {
moduleResult.setPassCount(moduleResult.getPassCount() + 1);
}
moduleResultMap.put(rootNodeId, moduleResult);
return;
}
});
}
private void getChildIds(TestCaseNodeDTO rootNode, Set<String> childIds) {
childIds.add(rootNode.getId());
List<TestCaseNodeDTO> children = rootNode.getChildren();
if(children != null) {
Iterator<TestCaseNodeDTO> iterator = children.iterator();
while(iterator.hasNext()){
getChildIds(iterator.next(), childIds);
}
}
}
} }

View File

@ -8,7 +8,7 @@
<el-row type="flex" justify="space-between"> <el-row type="flex" justify="space-between">
<el-col :span="12"> <el-col :span="12">
<span>所属项目</span> <span>所属项目</span>
<span class="item-value">{{reportInfo.project}}</span> <span class="item-value">{{reportInfo.projectName}}</span>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<span>测试负责人</span> <span>测试负责人</span>
@ -54,7 +54,7 @@
type: Object, type: Object,
default() { default() {
return { return {
project: '项目名称', projectName: '项目名称',
principal: '由丽媛', principal: '由丽媛',
executors: ['由丽媛','王振','陈建星'], executors: ['由丽媛','王振','陈建星'],
startTime: '2020-6-18', startTime: '2020-6-18',

View File

@ -4,7 +4,7 @@
<template> <template>
<ms-pie-chart :text="'测试结果统计图'" :name="'测试结果'" :data="charData"/> <ms-pie-chart v-if="isShow" :text="'测试结果统计图'" :name="'测试结果'" :data="charData"/>
</template> </template>
@ -21,38 +21,48 @@
components: {MsPieChart, CommonComponent}, components: {MsPieChart, CommonComponent},
data() { data() {
return { return {
charData: [ dataMap: new Map([
{ ["Pass", {value:235, name:'通过', itemStyle: {color: '#67C23A'}}],
value:235, name:'通过', ["Blocking", {value:274, name:'阻塞', itemStyle: {color: '#E6A23C'}}],
itemStyle: { ["Skip", {value:335, name:'跳过', itemStyle: {color: '#909399'}}],
color: '#67C23A' ["Prepare", {value:265, name:'未开始', itemStyle: {color: '#DEDE10'}}],
} ["Failure", {value:310, name:'失败', itemStyle: {color: '#F56C6C'}}],
}, ["Underway", {value:245, name:'进行中', itemStyle: {color: 'lightskyblue'}}]
{ ]),
value:274, name:'阻塞', charData: [],
itemStyle: { isShow: true
color: '#E6A23C' }
} },
}, props: {
{ executeResult: {
value:310, name:'失败', type: Array
itemStyle: { }
color: '#F56C6C' },
} watch: {
}, executeResult() {
{ this.charData = [];
value:335, name:'跳过', this.executeResult.forEach(item => {
itemStyle: { let data = this.dataMap.get(item.status);
color: '#909399' data.value = item.count;
} this.charData.push(data);
}, });
{ this.reload();
value:400, name:'未完成', }
itemStyle: { },
color: 'lightskyblue' created() {
} this.charData.push(this.dataMap.get('Pass'));
} this.charData.push(this.dataMap.get('Blocking'));
] this.charData.push(this.dataMap.get('Skip'));
this.charData.push(this.dataMap.get('Prepare'));
this.charData.push(this.dataMap.get('Failure'));
this.charData.push(this.dataMap.get('Underway'));
},
methods: {
reload() {
this.isShow = false;
this.$nextTick(function () {
this.isShow = true;
})
} }
} }
} }

View File

@ -1,14 +1,13 @@
<template> <template>
<common-component :title="'测试结果'"> <common-component :title="'测试结果'">
<template> <template>
<el-table <el-table
:data="testResults" :data="testResults"
stripe stripe
style="width: 100%"> style="width: 100%">
<el-table-column <el-table-column
prop="module" prop="moduleName"
:label="'模块'" :label="'模块'"
width="180"> width="180">
</el-table-column> </el-table-column>
@ -20,6 +19,9 @@
<el-table-column <el-table-column
prop="passRate" prop="passRate"
:label="'通过率'"> :label="'通过率'">
<template v-slot:default="scope">
{{scope.row.passRate}}%
</template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="flawCount" prop="flawCount"
@ -37,29 +39,25 @@
export default { export default {
name: "TestResultComponent", name: "TestResultComponent",
components: {CommonComponent}, components: {CommonComponent},
data() {
return {
}
},
props: { props: {
testResults: { testResults: {
type: Array, type: Array,
default() { default() {
return [ return [
{ {
module: '模块1', moduleName: '模块1',
caseCount: '14', caseCount: '14',
passRate: 10.8, passRate: 10.8,
flawCount: 3 flawCount: 3
}, },
{ {
module: '模块2', moduleName: '模块2',
caseCount: '24', caseCount: '24',
passRate: 40, passRate: 40,
flawCount: 6 flawCount: 6
}, },
{ {
module: '模块3', moduleName: '模块3',
caseCount: '50', caseCount: '50',
passRate: 76.9, passRate: 76.9,
flawCount: 8 flawCount: 8

View File

@ -108,7 +108,7 @@
this.isRouterAlive = false; this.isRouterAlive = false;
this.$nextTick(function () { this.$nextTick(function () {
this.isRouterAlive = true; this.isRouterAlive = true;
}) });
} }
} }
} }

View File

@ -26,9 +26,9 @@
<div class="container"> <div class="container">
<el-main> <el-main>
<div class="preview" v-for="item in previews" :key="item.id"> <div class="preview" v-for="item in previews" :key="item.id">
<base-info-component v-if="item.id == 1"/> <base-info-component :report-info="metric" v-if="item.id == 1"/>
<test-result-component v-if="item.id == 2"/> <test-result-component :test-results="metric.moduleExecuteResult" v-if="item.id == 2"/>
<test-result-chart-component v-if="item.id == 3"/> <test-result-chart-component :execute-result="metric.executeResult" v-if="item.id == 3"/>
<rich-text-component :preview="item" v-if="item.type != 'system'"/> <rich-text-component :preview="item" v-if="item.type != 'system'"/>
</div> </div>
</el-main> </el-main>
@ -61,6 +61,7 @@
previews: [], previews: [],
report: {}, report: {},
reportId: '', reportId: '',
metric: {},
componentMap: new Map( componentMap: new Map(
[ [
[1, { name: "基础信息", id: 1 , type: 'system'}], [1, { name: "基础信息", id: 1 , type: 'system'}],
@ -71,6 +72,11 @@
) )
} }
}, },
props: {
planId: {
type: String
}
},
methods: { methods: {
open(id) { open(id) {
if (id) { if (id) {
@ -86,6 +92,7 @@
if (this.report.content.customComponent) { if (this.report.content.customComponent) {
this.report.content.customComponent = jsonToMap(this.report.content.customComponent); this.report.content.customComponent = jsonToMap(this.report.content.customComponent);
} }
this.getMetric();
this.initPreviews(); this.initPreviews();
}); });
}, },
@ -110,6 +117,13 @@
}, },
handleEdit() { handleEdit() {
this.$refs.templateEdit.open(this.reportId, true); this.$refs.templateEdit.open(this.reportId, true);
},
getMetric() {
this.result = this.$get('/case/report/get/metric/' + this.planId, response => {
this.metric = response.data;
this.metric.startTime = this.report.startTime;
this.metric.endTime = this.report.endTime;
});
} }
} }
} }

View File

@ -109,7 +109,7 @@
@refreshTable="search"/> @refreshTable="search"/>
<test-report-template-list @openReport="openReport" :plan-id="planId" ref="testReporTtemplateList"/> <test-report-template-list @openReport="openReport" :plan-id="planId" ref="testReporTtemplateList"/>
<test-case-report-view ref="testCaseReportView"/> <test-case-report-view :plan-id="planId" ref="testCaseReportView"/>
</el-card> </el-card>
</template> </template>