feat(测试计划): 补充报告详情功能
This commit is contained in:
parent
0ff9b831cd
commit
2a3421f91d
|
@ -2,11 +2,15 @@ package io.metersphere.plan.controller;
|
||||||
|
|
||||||
import com.github.pagehelper.Page;
|
import com.github.pagehelper.Page;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
|
import io.metersphere.bug.dto.response.BugDTO;
|
||||||
|
import io.metersphere.functional.dto.FunctionalCasePageDTO;
|
||||||
import io.metersphere.plan.constants.TestPlanResourceConfig;
|
import io.metersphere.plan.constants.TestPlanResourceConfig;
|
||||||
import io.metersphere.plan.domain.TestPlanReport;
|
import io.metersphere.plan.domain.TestPlanReport;
|
||||||
import io.metersphere.plan.dto.request.TestPlanReportBatchRequest;
|
import io.metersphere.plan.dto.request.TestPlanReportBatchRequest;
|
||||||
|
import io.metersphere.plan.dto.request.TestPlanReportDetailPageRequest;
|
||||||
import io.metersphere.plan.dto.request.TestPlanReportGenRequest;
|
import io.metersphere.plan.dto.request.TestPlanReportGenRequest;
|
||||||
import io.metersphere.plan.dto.request.TestPlanReportPageRequest;
|
import io.metersphere.plan.dto.request.TestPlanReportPageRequest;
|
||||||
|
import io.metersphere.plan.dto.response.TestPlanReportDetailResponse;
|
||||||
import io.metersphere.plan.dto.response.TestPlanReportPageResponse;
|
import io.metersphere.plan.dto.response.TestPlanReportPageResponse;
|
||||||
import io.metersphere.plan.service.TestPlanManagementService;
|
import io.metersphere.plan.service.TestPlanManagementService;
|
||||||
import io.metersphere.plan.service.TestPlanReportLogService;
|
import io.metersphere.plan.service.TestPlanReportLogService;
|
||||||
|
@ -87,4 +91,32 @@ public class TestPlanReportController {
|
||||||
public TestPlanReport genReportByManual(@Validated @RequestBody TestPlanReportGenRequest request) {
|
public TestPlanReport genReportByManual(@Validated @RequestBody TestPlanReportGenRequest request) {
|
||||||
return testPlanReportService.genReportByManual(request, SessionUtils.getUserId());
|
return testPlanReportService.genReportByManual(request, SessionUtils.getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get/{id}")
|
||||||
|
@Operation(summary = "测试计划-报告-详情")
|
||||||
|
@RequiresPermissions(PermissionConstants.TEST_PLAN_REPORT_READ)
|
||||||
|
@CheckOwner(resourceId = "#id", resourceType = "test_plan_report")
|
||||||
|
public TestPlanReportDetailResponse get(@PathVariable String id) {
|
||||||
|
return testPlanReportService.getReport(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/detail/bug/page")
|
||||||
|
@Operation(summary = "测试计划-报告-详情-缺陷分页查询")
|
||||||
|
@RequiresPermissions(PermissionConstants.TEST_PLAN_REPORT_READ)
|
||||||
|
@CheckOwner(resourceId = "#request.getReportId()", resourceType = "test_plan_report")
|
||||||
|
public Pager<List<BugDTO>> pageBug(@Validated @RequestBody TestPlanReportDetailPageRequest request) {
|
||||||
|
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
|
||||||
|
StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "b.num desc");
|
||||||
|
return PageUtils.setPageInfo(page, testPlanReportService.listReportDetailBugs(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/detail/functional/case/page")
|
||||||
|
@Operation(summary = "测试计划-报告-详情-功能用例分页查询")
|
||||||
|
@RequiresPermissions(PermissionConstants.TEST_PLAN_REPORT_READ)
|
||||||
|
@CheckOwner(resourceId = "#request.getReportId()", resourceType = "test_plan_report")
|
||||||
|
public Pager<List<FunctionalCasePageDTO>> pageFunctionalCase(@Validated @RequestBody TestPlanReportDetailPageRequest request) {
|
||||||
|
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
|
||||||
|
StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "fc.num desc");
|
||||||
|
return PageUtils.setPageInfo(page, testPlanReportService.listReportDetailFunctionalCases(request));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package io.metersphere.plan.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class CaseStatusCountMap {
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
private Long count;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package io.metersphere.plan.dto.request;
|
||||||
|
|
||||||
|
import io.metersphere.system.dto.sdk.BasePageRequest;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class TestPlanReportDetailPageRequest extends BasePageRequest {
|
||||||
|
|
||||||
|
@Schema(description = "报告ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotBlank(message = "{test_plan.report_id.not_blank}")
|
||||||
|
private String reportId;
|
||||||
|
|
||||||
|
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotBlank(message = "{test_plan.report_id.not_blank}")
|
||||||
|
private String projectId;
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package io.metersphere.plan.dto.response;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class TestPlanReportDetailResponse {
|
||||||
|
|
||||||
|
@Schema(description = "报告ID")
|
||||||
|
private String id;
|
||||||
|
@Schema(description = "报告名称")
|
||||||
|
private String name;
|
||||||
|
@Schema(description = "报告开始时间")
|
||||||
|
private Long startTime;
|
||||||
|
@Schema(description = "报告执行开始时间")
|
||||||
|
private Long executeTime;
|
||||||
|
@Schema(description = "报告结束(执行)时间")
|
||||||
|
private Long ednTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 报告分析
|
||||||
|
*/
|
||||||
|
@Schema(description = "通过阈值")
|
||||||
|
private Double passThreshold;
|
||||||
|
@Schema(description = "通过率")
|
||||||
|
private Double passRate;
|
||||||
|
@Schema(description = "执行完成率")
|
||||||
|
private Double executeRate;
|
||||||
|
@Schema(description = "缺陷总数")
|
||||||
|
private Integer bugCount;
|
||||||
|
|
||||||
|
|
||||||
|
@Schema(description = "用例总数")
|
||||||
|
private Integer caseTotal = 0;
|
||||||
|
/**
|
||||||
|
* 执行分析
|
||||||
|
*/
|
||||||
|
@Schema(description = "执行分析-用例数")
|
||||||
|
private CaseCount executeCount;
|
||||||
|
/**
|
||||||
|
* 功能用例分析
|
||||||
|
*/
|
||||||
|
@Schema(description = "功能用例分析-用例数")
|
||||||
|
private CaseCount functionalCount;
|
||||||
|
/**
|
||||||
|
* 接口用例分析
|
||||||
|
*/
|
||||||
|
@Schema(description = "接口用例分析-用例数")
|
||||||
|
private CaseCount apiCaseCount;
|
||||||
|
/**
|
||||||
|
* 接口场景用例分析
|
||||||
|
*/
|
||||||
|
@Schema(description = "接口场景用例分析-用例数")
|
||||||
|
private CaseCount apiScenarioCount;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能, 接口, 场景
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class CaseCount {
|
||||||
|
@Schema(description = "成功用例数量")
|
||||||
|
private Integer success = 0;
|
||||||
|
@Schema(description = "失败用例数量")
|
||||||
|
private Integer error = 0;
|
||||||
|
@Schema(description = "误报用例数量")
|
||||||
|
private Integer fakeError = 0;
|
||||||
|
@Schema(description = "阻塞用例数量")
|
||||||
|
private Integer block = 0;
|
||||||
|
@Schema(description = "未执行用例数量")
|
||||||
|
private Integer pending = 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,11 @@
|
||||||
package io.metersphere.plan.mapper;
|
package io.metersphere.plan.mapper;
|
||||||
|
|
||||||
|
import io.metersphere.bug.dto.response.BugDTO;
|
||||||
|
import io.metersphere.functional.dto.FunctionalCasePageDTO;
|
||||||
import io.metersphere.plan.domain.TestPlanReport;
|
import io.metersphere.plan.domain.TestPlanReport;
|
||||||
|
import io.metersphere.plan.dto.CaseStatusCountMap;
|
||||||
import io.metersphere.plan.dto.request.TestPlanReportBatchRequest;
|
import io.metersphere.plan.dto.request.TestPlanReportBatchRequest;
|
||||||
|
import io.metersphere.plan.dto.request.TestPlanReportDetailPageRequest;
|
||||||
import io.metersphere.plan.dto.request.TestPlanReportPageRequest;
|
import io.metersphere.plan.dto.request.TestPlanReportPageRequest;
|
||||||
import io.metersphere.plan.dto.response.TestPlanReportPageResponse;
|
import io.metersphere.plan.dto.response.TestPlanReportPageResponse;
|
||||||
import io.metersphere.system.dto.sdk.ApiReportMessageDTO;
|
import io.metersphere.system.dto.sdk.ApiReportMessageDTO;
|
||||||
|
@ -37,4 +41,25 @@ public interface ExtTestPlanReportMapper {
|
||||||
List<TestPlanReport> selectReportByIds(@Param("ids") List<String> ids);
|
List<TestPlanReport> selectReportByIds(@Param("ids") List<String> ids);
|
||||||
|
|
||||||
List<ApiReportMessageDTO> getNoticeList(@Param("ids") List<String> subList);
|
List<ApiReportMessageDTO> getNoticeList(@Param("ids") List<String> subList);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统计报告中功能用例执行情况
|
||||||
|
* @param reportId 报告ID
|
||||||
|
* @return 用例数量
|
||||||
|
*/
|
||||||
|
List<CaseStatusCountMap> countFunctionalCaseExecuteResult(@Param("id") String reportId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询报告关联的缺陷
|
||||||
|
* @param request 请求参数
|
||||||
|
* @return 关联的缺陷集合
|
||||||
|
*/
|
||||||
|
List<BugDTO> listReportBugs(@Param("request")TestPlanReportDetailPageRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询报告关联的用例
|
||||||
|
* @param request 请求参数
|
||||||
|
* @return 关联的用例集合
|
||||||
|
*/
|
||||||
|
List<FunctionalCasePageDTO> listReportFunctionalCases(@Param("request")TestPlanReportDetailPageRequest request);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,24 @@
|
||||||
where tprfc.test_plan_report_id = #{id} and tprfc.execute_result = 'SUCCESS'
|
where tprfc.test_plan_report_id = #{id} and tprfc.execute_result = 'SUCCESS'
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="countFunctionalCaseExecuteResult" resultType="io.metersphere.plan.dto.CaseStatusCountMap">
|
||||||
|
select execute_result as status, count(*) as count from test_plan_report_function_case
|
||||||
|
where test_plan_report_id = #{id}
|
||||||
|
group by execute_result
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="listReportBugs" resultType="io.metersphere.bug.dto.response.BugDTO">
|
||||||
|
select distinct b.id as id, b.num as num, b.title as title, b.status as status, b.handle_user as handleUser
|
||||||
|
from test_plan_report_bug tprb inner join bug b on tprb.bug_id = b.id
|
||||||
|
where tprb.test_plan_report_id = #{request.reportId}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="listReportFunctionalCases" resultType="io.metersphere.functional.dto.FunctionalCasePageDTO">
|
||||||
|
select distinct fc.id as id, fc.num as num, fc.name as name, tprfc.execute_result as lastExecuteResult
|
||||||
|
from test_plan_report_function_case tprfc inner join functional_case fc on tprfc.function_case_id = fc.id
|
||||||
|
where tprfc.test_plan_report_id = #{request.reportId}
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="selectReportByIds" resultType="io.metersphere.plan.domain.TestPlanReport">
|
<select id="selectReportByIds" resultType="io.metersphere.plan.domain.TestPlanReport">
|
||||||
select * from test_plan_report where id in
|
select * from test_plan_report where id in
|
||||||
<foreach collection="ids" item="id" open="(" close=")" separator=",">
|
<foreach collection="ids" item="id" open="(" close=")" separator=",">
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
package io.metersphere.plan.service;
|
package io.metersphere.plan.service;
|
||||||
|
|
||||||
import io.metersphere.bug.mapper.BugRelationCaseMapper;
|
import io.metersphere.bug.dto.response.BugDTO;
|
||||||
import io.metersphere.bug.mapper.ExtBugRelateCaseMapper;
|
import io.metersphere.bug.mapper.ExtBugRelateCaseMapper;
|
||||||
|
import io.metersphere.bug.service.BugService;
|
||||||
|
import io.metersphere.functional.dto.FunctionalCasePageDTO;
|
||||||
import io.metersphere.plan.domain.*;
|
import io.metersphere.plan.domain.*;
|
||||||
|
import io.metersphere.plan.dto.CaseStatusCountMap;
|
||||||
import io.metersphere.plan.dto.TestPlanReportGenPreParam;
|
import io.metersphere.plan.dto.TestPlanReportGenPreParam;
|
||||||
import io.metersphere.plan.dto.TestPlanReportPostParam;
|
import io.metersphere.plan.dto.TestPlanReportPostParam;
|
||||||
import io.metersphere.plan.dto.request.TestPlanReportBatchRequest;
|
import io.metersphere.plan.dto.request.TestPlanReportBatchRequest;
|
||||||
|
import io.metersphere.plan.dto.request.TestPlanReportDetailPageRequest;
|
||||||
import io.metersphere.plan.dto.request.TestPlanReportGenRequest;
|
import io.metersphere.plan.dto.request.TestPlanReportGenRequest;
|
||||||
import io.metersphere.plan.dto.request.TestPlanReportPageRequest;
|
import io.metersphere.plan.dto.request.TestPlanReportPageRequest;
|
||||||
|
import io.metersphere.plan.dto.response.TestPlanReportDetailResponse;
|
||||||
import io.metersphere.plan.dto.response.TestPlanReportPageResponse;
|
import io.metersphere.plan.dto.response.TestPlanReportPageResponse;
|
||||||
import io.metersphere.plan.mapper.*;
|
import io.metersphere.plan.mapper.*;
|
||||||
import io.metersphere.sdk.constants.ExecStatus;
|
import io.metersphere.sdk.constants.*;
|
||||||
import io.metersphere.sdk.constants.ReportStatus;
|
|
||||||
import io.metersphere.sdk.constants.TaskTriggerMode;
|
|
||||||
import io.metersphere.sdk.constants.TestPlanConstants;
|
|
||||||
import io.metersphere.sdk.exception.MSException;
|
import io.metersphere.sdk.exception.MSException;
|
||||||
import io.metersphere.sdk.util.BeanUtils;
|
import io.metersphere.sdk.util.BeanUtils;
|
||||||
import io.metersphere.sdk.util.DateUtils;
|
import io.metersphere.sdk.util.DateUtils;
|
||||||
|
@ -37,6 +39,7 @@ import java.text.DecimalFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class TestPlanReportService {
|
public class TestPlanReportService {
|
||||||
|
@ -48,6 +51,8 @@ public class TestPlanReportService {
|
||||||
@Resource
|
@Resource
|
||||||
private SqlSessionFactory sqlSessionFactory;
|
private SqlSessionFactory sqlSessionFactory;
|
||||||
@Resource
|
@Resource
|
||||||
|
private BugService bugService;
|
||||||
|
@Resource
|
||||||
private TestPlanMapper testPlanMapper;
|
private TestPlanMapper testPlanMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private TestPlanConfigMapper testPlanConfigMapper;
|
private TestPlanConfigMapper testPlanConfigMapper;
|
||||||
|
@ -56,8 +61,6 @@ public class TestPlanReportService {
|
||||||
@Resource
|
@Resource
|
||||||
private ExtBugRelateCaseMapper extBugRelateCaseMapper;
|
private ExtBugRelateCaseMapper extBugRelateCaseMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private BugRelationCaseMapper bugRelationCaseMapper;
|
|
||||||
@Resource
|
|
||||||
private ExtTestPlanReportMapper extTestPlanReportMapper;
|
private ExtTestPlanReportMapper extTestPlanReportMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private TestPlanReportLogService testPlanReportLogService;
|
private TestPlanReportLogService testPlanReportLogService;
|
||||||
|
@ -153,6 +156,10 @@ public class TestPlanReportService {
|
||||||
TestPlanReportPostParam postParam = new TestPlanReportPostParam();
|
TestPlanReportPostParam postParam = new TestPlanReportPostParam();
|
||||||
BeanUtils.copyBean(postParam, request);
|
BeanUtils.copyBean(postParam, request);
|
||||||
postParam.setReportId(preReport.getId());
|
postParam.setReportId(preReport.getId());
|
||||||
|
// 手动生成报告, 执行状态为已完成, 执行及结束时间为当前时间
|
||||||
|
postParam.setExecuteTime(System.currentTimeMillis());
|
||||||
|
postParam.setEndTime(System.currentTimeMillis());
|
||||||
|
postParam.setExecStatus(ExecStatus.COMPLETED.name());
|
||||||
return postHandleReport(postParam);
|
return postHandleReport(postParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,15 +260,15 @@ public class TestPlanReportService {
|
||||||
example.createCriteria().andTestPlanReportIdEqualTo(postParam.getReportId());
|
example.createCriteria().andTestPlanReportIdEqualTo(postParam.getReportId());
|
||||||
TestPlanReportSummary reportSummary = testPlanReportSummaryMapper.selectByExample(example).get(0);
|
TestPlanReportSummary reportSummary = testPlanReportSummaryMapper.selectByExample(example).get(0);
|
||||||
DecimalFormat rateFormat = new DecimalFormat("#0.0000");
|
DecimalFormat rateFormat = new DecimalFormat("#0.0000");
|
||||||
rateFormat.setMinimumFractionDigits(2);
|
rateFormat.setMinimumFractionDigits(4);
|
||||||
rateFormat.setMaximumFractionDigits(2);
|
rateFormat.setMaximumFractionDigits(4);
|
||||||
// 通过的功能用例数
|
// 通过的功能用例数
|
||||||
// TODO: 接口用例, 场景用例
|
// TODO: 接口用例, 场景用例
|
||||||
long functionalCasePassCount = extTestPlanReportMapper.countExecuteSuccessFunctionalCase(postParam.getReportId());
|
long functionalCasePassCount = extTestPlanReportMapper.countExecuteSuccessFunctionalCase(postParam.getReportId());
|
||||||
// 用例总数
|
// 用例总数
|
||||||
long caseTotal = reportSummary.getFunctionalCaseCount() + reportSummary.getApiCaseCount() + reportSummary.getApiScenarioCount();
|
long caseTotal = reportSummary.getFunctionalCaseCount() + reportSummary.getApiCaseCount() + reportSummary.getApiScenarioCount();
|
||||||
// 通过率 {通过用例数/总用例数}
|
// 通过率 {通过用例数/总用例数}
|
||||||
double passRate = (functionalCasePassCount == 0 || caseTotal == 0) ? 0.00 :
|
double passRate = (functionalCasePassCount == 0 || caseTotal == 0) ? 0.0000 :
|
||||||
Double.parseDouble(rateFormat.format((double) functionalCasePassCount / (double) caseTotal));
|
Double.parseDouble(rateFormat.format((double) functionalCasePassCount / (double) caseTotal));
|
||||||
// FIXME: 后续替换成PASS_COUNT {保留该逻辑, 四舍五入导致的边界值数据展示偏差}
|
// FIXME: 后续替换成PASS_COUNT {保留该逻辑, 四舍五入导致的边界值数据展示偏差}
|
||||||
if (passRate == 0 && functionalCasePassCount > 0) {
|
if (passRate == 0 && functionalCasePassCount > 0) {
|
||||||
|
@ -275,6 +282,93 @@ public class TestPlanReportService {
|
||||||
return planReport;
|
return planReport;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取报告分析详情
|
||||||
|
* @param reportId 报告ID
|
||||||
|
* @return 报告分析详情
|
||||||
|
*/
|
||||||
|
public TestPlanReportDetailResponse getReport(String reportId) {
|
||||||
|
TestPlanReport planReport = checkReport(reportId);
|
||||||
|
TestPlanReportSummaryExample example = new TestPlanReportSummaryExample();
|
||||||
|
example.createCriteria().andTestPlanReportIdEqualTo(reportId);
|
||||||
|
TestPlanReportSummary reportSummary = testPlanReportSummaryMapper.selectByExample(example).get(0);
|
||||||
|
TestPlanReportDetailResponse planReportDetail = new TestPlanReportDetailResponse();
|
||||||
|
BeanUtils.copyBean(planReportDetail, planReport);
|
||||||
|
int caseTotal = (int) (reportSummary.getFunctionalCaseCount() + reportSummary.getApiCaseCount() + reportSummary.getApiScenarioCount());
|
||||||
|
planReportDetail.setCaseTotal(caseTotal);
|
||||||
|
planReportDetail.setBugCount(reportSummary.getBugCount().intValue());
|
||||||
|
/*
|
||||||
|
* 统计用例执行数据
|
||||||
|
*/
|
||||||
|
return statisticsCase(planReportDetail);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询报告详情-缺陷分页数据
|
||||||
|
* @param request 请求参数
|
||||||
|
* @return 缺陷分页数据
|
||||||
|
*/
|
||||||
|
public List<BugDTO> listReportDetailBugs(TestPlanReportDetailPageRequest request) {
|
||||||
|
List<BugDTO> bugs = extTestPlanReportMapper.listReportBugs(request);
|
||||||
|
return bugService.handleCustomField(bugs, request.getProjectId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询报告详情-缺陷分页数据
|
||||||
|
* @param request 请求参数
|
||||||
|
* @return 缺陷分页数据
|
||||||
|
*/
|
||||||
|
public List<FunctionalCasePageDTO> listReportDetailFunctionalCases(TestPlanReportDetailPageRequest request) {
|
||||||
|
return extTestPlanReportMapper.listReportFunctionalCases(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统计用例执行数据 (目前只统计功能用例)
|
||||||
|
* @param reportDetail 用例详情
|
||||||
|
*/
|
||||||
|
private TestPlanReportDetailResponse statisticsCase(TestPlanReportDetailResponse reportDetail) {
|
||||||
|
// 功能用例 (无误报状态)
|
||||||
|
List<CaseStatusCountMap> functionalCaseCountMap = extTestPlanReportMapper.countFunctionalCaseExecuteResult(reportDetail.getId());
|
||||||
|
Map<String, Long> functionalCaseResultMap = functionalCaseCountMap.stream().collect(Collectors.toMap(CaseStatusCountMap::getStatus, CaseStatusCountMap::getCount));
|
||||||
|
TestPlanReportDetailResponse.CaseCount functionalCaseCount = new TestPlanReportDetailResponse.CaseCount();
|
||||||
|
functionalCaseCount.setSuccess(functionalCaseResultMap.getOrDefault(FunctionalCaseExecuteResult.SUCCESS.name(), 0L).intValue());
|
||||||
|
functionalCaseCount.setError(functionalCaseResultMap.getOrDefault(FunctionalCaseExecuteResult.ERROR.name(), 0L).intValue());
|
||||||
|
functionalCaseCount.setPending(functionalCaseResultMap.getOrDefault(FunctionalCaseExecuteResult.PENDING.name(), 0L).intValue());
|
||||||
|
functionalCaseCount.setBlock(functionalCaseResultMap.getOrDefault(FunctionalCaseExecuteResult.BLOCKED.name(), 0L).intValue());
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: 接口用例, 场景用例
|
||||||
|
|
||||||
|
// FIXME: 目前只有功能用例
|
||||||
|
TestPlanReportDetailResponse.CaseCount executeCaseCount = new TestPlanReportDetailResponse.CaseCount();
|
||||||
|
executeCaseCount.setSuccess(functionalCaseCount.getSuccess());
|
||||||
|
executeCaseCount.setError(functionalCaseCount.getError());
|
||||||
|
executeCaseCount.setFakeError(functionalCaseCount.getFakeError());
|
||||||
|
executeCaseCount.setPending(functionalCaseCount.getPending());
|
||||||
|
executeCaseCount.setBlock(functionalCaseCount.getBlock());
|
||||||
|
|
||||||
|
// 计算执行完成率
|
||||||
|
DecimalFormat rateFormat = new DecimalFormat("#0.00");
|
||||||
|
rateFormat.setMinimumFractionDigits(2);
|
||||||
|
rateFormat.setMaximumFractionDigits(2);
|
||||||
|
// 执行完成率 {已执行用例数/总用例数}
|
||||||
|
double executeRate = (executeCaseCount.getPending().equals(reportDetail.getCaseTotal()) || reportDetail.getCaseTotal() == 0) ? 0.00 :
|
||||||
|
Double.parseDouble(rateFormat.format((double) (reportDetail.getCaseTotal() - executeCaseCount.getPending()) / (double) reportDetail.getCaseTotal()));
|
||||||
|
// FIXME: 后续替换成PASS_COUNT {保留该逻辑, 四舍五入导致的边界值数据展示偏差}
|
||||||
|
if (executeRate == 0 && reportDetail.getCaseTotal() - executeCaseCount.getPending() > 0) {
|
||||||
|
executeRate = 0.01;
|
||||||
|
} else if (executeRate == 100 && executeCaseCount.getPending() > 0) {
|
||||||
|
executeRate = 99.99;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 详情数据
|
||||||
|
reportDetail.setExecuteRate(executeRate);
|
||||||
|
reportDetail.setFunctionalCount(functionalCaseCount);
|
||||||
|
reportDetail.setExecuteCount(executeCaseCount);
|
||||||
|
return reportDetail;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过请求参数获取批量操作的ID集合
|
* 通过请求参数获取批量操作的ID集合
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package io.metersphere.plan.controller;
|
package io.metersphere.plan.controller;
|
||||||
|
|
||||||
|
import io.metersphere.plan.domain.TestPlanReport;
|
||||||
import io.metersphere.plan.dto.TestPlanShareInfo;
|
import io.metersphere.plan.dto.TestPlanShareInfo;
|
||||||
import io.metersphere.plan.dto.request.*;
|
import io.metersphere.plan.dto.request.*;
|
||||||
import io.metersphere.plan.dto.response.TestPlanReportPageResponse;
|
import io.metersphere.plan.dto.response.TestPlanReportPageResponse;
|
||||||
|
@ -33,10 +34,15 @@ public class TestPlanReportControllerTests extends BaseTest {
|
||||||
private static final String DELETE_PLAN_REPORT = "/test-plan/report/delete";
|
private static final String DELETE_PLAN_REPORT = "/test-plan/report/delete";
|
||||||
private static final String BATCH_DELETE_PLAN_REPORT = "/test-plan/report/batch-delete";
|
private static final String BATCH_DELETE_PLAN_REPORT = "/test-plan/report/batch-delete";
|
||||||
private static final String GEN_PLAN_REPORT = "/test-plan/report/gen";
|
private static final String GEN_PLAN_REPORT = "/test-plan/report/gen";
|
||||||
|
private static final String GET_PLAN_REPORT = "/test-plan/report/get";
|
||||||
|
private static final String GET_PLAN_REPORT_DETAIL_BUG_PAGE = "/test-plan/report/detail/bug/page";
|
||||||
|
private static final String GET_PLAN_REPORT_DETAIL_FUNCTIONAL_PAGE = "/test-plan/report/detail/functional/case/page";
|
||||||
private static final String GEN_AND_SHARE = "/test-plan/report/share/gen";
|
private static final String GEN_AND_SHARE = "/test-plan/report/share/gen";
|
||||||
private static final String GET_SHARE_INFO = "/test-plan/report/share/get";
|
private static final String GET_SHARE_INFO = "/test-plan/report/share/get";
|
||||||
private static final String GET_SHARE_TIME = "/test-plan/report/share/get-share-time";
|
private static final String GET_SHARE_TIME = "/test-plan/report/share/get-share-time";
|
||||||
|
|
||||||
|
private static String GEN_REPORT_ID;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(1)
|
@Order(1)
|
||||||
@Sql(scripts = {"/dml/init_test_plan_report.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
|
@Sql(scripts = {"/dml/init_test_plan_report.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
|
||||||
|
@ -181,6 +187,44 @@ public class TestPlanReportControllerTests extends BaseTest {
|
||||||
genRequest.setTestPlanId("plan_id_for_gen_report_1");
|
genRequest.setTestPlanId("plan_id_for_gen_report_1");
|
||||||
this.requestPost(GEN_PLAN_REPORT, genRequest);
|
this.requestPost(GEN_PLAN_REPORT, genRequest);
|
||||||
genRequest.setTestPlanId("plan_id_for_gen_report");
|
genRequest.setTestPlanId("plan_id_for_gen_report");
|
||||||
this.requestPost(GEN_PLAN_REPORT, genRequest);
|
MvcResult mvcResult = this.requestPostAndReturn(GEN_PLAN_REPORT, genRequest);
|
||||||
|
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||||
|
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
|
||||||
|
//返回请求正常
|
||||||
|
Assertions.assertNotNull(resultHolder);
|
||||||
|
TestPlanReport report = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), TestPlanReport.class);
|
||||||
|
GEN_REPORT_ID = report.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(12)
|
||||||
|
void testGetReportSuccess() throws Exception {
|
||||||
|
this.requestGet(GET_PLAN_REPORT + "/" + GEN_REPORT_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(13)
|
||||||
|
void testPageReportDetailBugSuccess() throws Exception {
|
||||||
|
TestPlanReportDetailPageRequest request = new TestPlanReportDetailPageRequest();
|
||||||
|
request.setReportId(GEN_REPORT_ID);
|
||||||
|
request.setProjectId("100001100001");
|
||||||
|
request.setCurrent(1);
|
||||||
|
request.setPageSize(10);
|
||||||
|
this.requestPostWithOk(GET_PLAN_REPORT_DETAIL_BUG_PAGE, request);
|
||||||
|
request.setSort(Map.of("num", "asc"));
|
||||||
|
this.requestPostWithOk(GET_PLAN_REPORT_DETAIL_BUG_PAGE, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(14)
|
||||||
|
void testPageReportDetailFunctionalCaseSuccess() throws Exception {
|
||||||
|
TestPlanReportDetailPageRequest request = new TestPlanReportDetailPageRequest();
|
||||||
|
request.setReportId(GEN_REPORT_ID);
|
||||||
|
request.setProjectId("100001100001");
|
||||||
|
request.setCurrent(1);
|
||||||
|
request.setPageSize(10);
|
||||||
|
this.requestPostWithOk(GET_PLAN_REPORT_DETAIL_FUNCTIONAL_PAGE, request);
|
||||||
|
request.setSort(Map.of("num", "asc"));
|
||||||
|
this.requestPostWithOk(GET_PLAN_REPORT_DETAIL_FUNCTIONAL_PAGE, request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,20 @@ INSERT INTO `test_plan_config`(`test_plan_id`, `automatic_status_update`, `repea
|
||||||
|
|
||||||
-- 计划关联用例执行的测试数据
|
-- 计划关联用例执行的测试数据
|
||||||
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`) VALUES
|
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`) VALUES
|
||||||
('plan_id_for_gen_report_case_1', 'plan_id_for_gen_report', 'f1', CURRENT_TIMESTAMP, 'admin', 'admin', CURRENT_TIMESTAMP, 'PENDING', 1),
|
('plan_id_for_gen_report_case_1', 'plan_id_for_gen_report', 'f1_gen', CURRENT_TIMESTAMP, 'admin', 'admin', CURRENT_TIMESTAMP, 'PENDING', 1),
|
||||||
('plan_id_for_gen_report_case_2', 'plan_id_for_gen_report', 'f2', CURRENT_TIMESTAMP, 'admin', 'admin', CURRENT_TIMESTAMP, 'SUCCESS', 2),
|
('plan_id_for_gen_report_case_2', 'plan_id_for_gen_report', 'f2_gen', CURRENT_TIMESTAMP, 'admin', 'admin', CURRENT_TIMESTAMP, 'SUCCESS', 2),
|
||||||
('plan_id_for_gen_report_case_3', 'plan_id_for_gen_report', 'f3', CURRENT_TIMESTAMP, 'admin', 'admin', CURRENT_TIMESTAMP, 'ERROR', 3),
|
('plan_id_for_gen_report_case_3', 'plan_id_for_gen_report', 'f3_gen', CURRENT_TIMESTAMP, 'admin', 'admin', CURRENT_TIMESTAMP, 'ERROR', 3),
|
||||||
('plan_id_for_gen_report_case_4', 'plan_id_for_gen_report', 'f4', CURRENT_TIMESTAMP, 'admin', 'admin', CURRENT_TIMESTAMP, 'BLOCKED', 4),
|
('plan_id_for_gen_report_case_4', 'plan_id_for_gen_report', 'f4_gen', CURRENT_TIMESTAMP, 'admin', 'admin', CURRENT_TIMESTAMP, 'BLOCKED', 4),
|
||||||
('plan_id_for_gen_report_case_5', 'plan_id_for_gen_report', 'f5', CURRENT_TIMESTAMP, 'admin', 'admin', CURRENT_TIMESTAMP, 'FAKE_ERROR', 5);
|
('plan_id_for_gen_report_case_5', 'plan_id_for_gen_report', 'f5_gen', CURRENT_TIMESTAMP, 'admin', 'admin', CURRENT_TIMESTAMP, 'FAKE_ERROR', 5);
|
||||||
|
|
||||||
-- 计划关联缺陷的测试数据
|
-- 计划关联缺陷的测试数据
|
||||||
INSERT INTO `bug_relation_case`(`id`, `case_id`, `bug_id`, `case_type`, `test_plan_id`, `test_plan_case_id`, `create_user`, `create_time`, `update_time`) VALUES
|
INSERT INTO `bug_relation_case`(`id`, `case_id`, `bug_id`, `case_type`, `test_plan_id`, `test_plan_case_id`, `create_user`, `create_time`, `update_time`) VALUES
|
||||||
('test-plan-bug-relate-case-1', 'f1', 'test-plan-bug-id', 'FUNCTIONAL', 'plan_id_for_gen_report', 'f1', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
|
('test-plan-bug-relate-case-1', 'f1', 'test-plan-bug-for-gen', 'FUNCTIONAL', 'plan_id_for_gen_report', 'f1', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
|
||||||
|
|
||||||
|
-- 缺陷的测试数据
|
||||||
|
INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time, update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tags, platform_bug_id, deleted, pos) VALUES
|
||||||
|
('test-plan-bug-for-gen', 100000, 'default-bug-gen', 'oasis', 'admin', 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '100001100001', 'bug-template-id', 'Local', 'new', '["default-tag"]', null, 0, 5000);
|
||||||
|
|
||||||
|
-- 用例的测试数据
|
||||||
|
INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time)
|
||||||
|
VALUES ('f1_gen', 100001, 'TEST_MODULE_ID', '100001100001', '100001', 'functional_case_gen', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'v1.0.0', 'PENDING', b'0', b'0', b'1', 'admin', 'admin', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
|
Loading…
Reference in New Issue