refactor(测试计划): 测试计划状态重构

This commit is contained in:
Jianguo-Genius 2024-07-03 16:09:57 +08:00 committed by 建国
parent 54c102aad3
commit 01c7a365e0
29 changed files with 770 additions and 200 deletions

View File

@ -47,5 +47,10 @@ CALL UpdatePosForNoneGroup();
DROP PROCEDURE IF EXISTS UpdatePosForNoneGroup; DROP PROCEDURE IF EXISTS UpdatePosForNoneGroup;
-- 清洗测试计划表的pos数据结束 -- 清洗测试计划表的pos数据结束
-- 修改未归档测试计划的存储状态
UPDATE test_plan
SET status = 'NOT_ARCHIVED'
WHERE status != 'ARCHIVED';
-- set innodb lock wait timeout to default -- set innodb lock wait timeout to default
SET SESSION innodb_lock_wait_timeout = DEFAULT; SET SESSION innodb_lock_wait_timeout = DEFAULT;

View File

@ -5,19 +5,21 @@ public class TestPlanConstants {
public static final String TEST_PLAN_TYPE_PLAN = "TEST_PLAN"; public static final String TEST_PLAN_TYPE_PLAN = "TEST_PLAN";
//测试计划类型-测试计划组 //测试计划类型-测试计划组
public static final String TEST_PLAN_TYPE_GROUP = "GROUP"; public static final String TEST_PLAN_TYPE_GROUP = "GROUP";
//测试计划组默认ID //测试计划组默认ID
public static final String TEST_PLAN_DEFAULT_GROUP_ID = "NONE"; public static final String TEST_PLAN_DEFAULT_GROUP_ID = "NONE";
//测试计划中相关的默认父ID //测试计划中相关的默认父ID
public static final String DEFAULT_PARENT_ID = "NONE"; public static final String DEFAULT_PARENT_ID = "NONE";
//测试计划状态-未开始 //测试计划状态-未开始
public static final String TEST_PLAN_STATUS_PREPARED = "PREPARED"; public static final String TEST_PLAN_STATUS_NOT_ARCHIVED = "NOT_ARCHIVED";
//测试计划状态-进行中
public static final String TEST_PLAN_STATUS_UNDERWAY = "UNDERWAY";
//测试计划状态-已完成
public static final String TEST_PLAN_STATUS_COMPLETED = "COMPLETED";
//测试计划状态-已归档 //测试计划状态-已归档
public static final String TEST_PLAN_STATUS_ARCHIVED = "ARCHIVED"; public static final String TEST_PLAN_STATUS_ARCHIVED = "ARCHIVED";
//测试计划对外展示状态-未开始
public static final String TEST_PLAN_SHOW_STATUS_PREPARED = "PREPARED";
//测试计划对外展示状态-进行中
public static final String TEST_PLAN_SHOW_STATUS_UNDERWAY = "UNDERWAY";
//测试计划对外展示状态-已完成
public static final String TEST_PLAN_SHOW_STATUS_COMPLETED = "COMPLETED";
} }

View File

@ -17,9 +17,9 @@ import io.metersphere.system.utils.SessionUtils;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -36,10 +36,10 @@ import java.util.List;
@RequestMapping("/project/log") @RequestMapping("/project/log")
public class ProjectLogController { public class ProjectLogController {
@Autowired @Resource
private SimpleUserService simpleUserService; private SimpleUserService simpleUserService;
@Autowired @Resource
private OperationLogService operationLogService; private OperationLogService operationLogService;
@GetMapping("/user/list/{projectId}") @GetMapping("/user/list/{projectId}")

View File

@ -0,0 +1,9 @@
package io.metersphere.plan.dto;
import lombok.Data;
@Data
public class TestPlanGroupCountDTO {
private String groupId;
private long count;
}

View File

@ -0,0 +1,10 @@
package io.metersphere.plan.dto;
import lombok.Data;
@Data
public class TestPlanResourceExecResultDTO {
private String testPlanId;
private String execResult;
private String testPlanGroupId;
}

View File

@ -26,6 +26,9 @@ public class TestPlanTableRequest extends BasePageRequest {
@Schema(description = "通过Keyword过滤出的测试子计划的测试计划组id") @Schema(description = "通过Keyword过滤出的测试子计划的测试计划组id")
private List<String> keywordFilterIds; private List<String> keywordFilterIds;
@Schema(description = "通过其他条件查询出来的必须要包含的测试计划ID")
private List<String> innerIds;
public String getSortString() { public String getSortString() {
if (StringUtils.isEmpty(super.getSortString())) { if (StringUtils.isEmpty(super.getSortString())) {
return "t.update_time desc"; return "t.update_time desc";

View File

@ -16,8 +16,6 @@ public class TestPlanResponse extends TestPlanStatisticsResponse {
private long num; private long num;
@Schema(description = "名称") @Schema(description = "名称")
private String name; private String name;
@Schema(description = "状态")
private String status;
@Schema(description = "测试计划类型 测试计划/测试计划组") @Schema(description = "测试计划类型 测试计划/测试计划组")
private String type; private String type;
@Schema(description = "标签") @Schema(description = "标签")

View File

@ -2,6 +2,8 @@ package io.metersphere.plan.dto.response;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.metersphere.plan.serializer.CustomRateSerializer; import io.metersphere.plan.serializer.CustomRateSerializer;
import io.metersphere.plan.utils.RateCalculateUtils;
import io.metersphere.sdk.constants.TestPlanConstants;
import io.metersphere.system.dto.request.schedule.BaseScheduleConfigRequest; import io.metersphere.system.dto.request.schedule.BaseScheduleConfigRequest;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@ -16,7 +18,8 @@ public class TestPlanStatisticsResponse {
@Schema(description = "测试计划ID") @Schema(description = "测试计划ID")
private String id; private String id;
@Schema(description = "测试计划状态")
private String status;
@Schema(description = "测试计划通过阈值{0-100}") @Schema(description = "测试计划通过阈值{0-100}")
@JsonSerialize(using = CustomRateSerializer.class) @JsonSerialize(using = CustomRateSerializer.class)
private Double passThreshold; private Double passThreshold;
@ -33,31 +36,70 @@ public class TestPlanStatisticsResponse {
* 执行进度中的用例数量统计 * 执行进度中的用例数量统计
*/ */
@Schema(description = "成功用例数量") @Schema(description = "成功用例数量")
private Integer successCount = 0; private long successCount = 0;
@Schema(description = "失败用例数量") @Schema(description = "失败用例数量")
private Integer errorCount = 0; private long errorCount = 0;
@Schema(description = "误报用例数量") @Schema(description = "误报用例数量")
private Integer fakeErrorCount = 0; private long fakeErrorCount = 0;
@Schema(description = "阻塞用例数量") @Schema(description = "阻塞用例数量")
private Integer blockCount = 0; private long blockCount = 0;
@Schema(description = "未执行用例数量") @Schema(description = "未执行用例数量")
private Integer pendingCount = 0; private long pendingCount = 0;
/** /**
* 用例数中用例数量统计 * 用例数中用例数量统计
*/ */
@Schema(description = "用例总数") @Schema(description = "用例总数")
private Integer caseTotal = 0; private long caseTotal = 0;
@Schema(description = "功能用例数量") @Schema(description = "功能用例数量")
private Integer functionalCaseCount = 0; private long functionalCaseCount = 0;
@Schema(description = "接口用例数量") @Schema(description = "接口用例数量")
private Integer apiCaseCount = 0; private long apiCaseCount = 0;
@Schema(description = "接口场景数量") @Schema(description = "接口场景数量")
private Integer apiScenarioCount = 0; private long apiScenarioCount = 0;
@Schema(description = "缺陷数量") @Schema(description = "缺陷数量")
private Integer bugCount = 0; private long bugCount = 0;
@Schema(description = "定时任务配置") @Schema(description = "定时任务配置")
private BaseScheduleConfigRequest scheduleConfig; private BaseScheduleConfigRequest scheduleConfig;
@Schema(description = "定时任务下一次执行时间") @Schema(description = "定时任务下一次执行时间")
private Long nextTriggerTime; private Long nextTriggerTime;
/**
* 计算测试计划状态
* 未开始执行进度0%
* 进行中执行进度不到100%
* 已完成执行进度100%
*/
public void calculateStatus() {
if (this.successCount == 0 && errorCount == 0 && fakeErrorCount == 0 && blockCount == 0) {
this.status = TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED;
} else if (this.pendingCount == 0) {
this.status = TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED;
} else {
this.status = TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY;
}
}
public void calculateCaseTotal() {
this.caseTotal = this.functionalCaseCount + this.apiCaseCount + this.apiScenarioCount;
}
public void calculatePassRate() {
this.passRate = RateCalculateUtils.divWithPrecision(this.successCount, this.caseTotal, 2);
}
public void calculateExecuteRate() {
this.executeRate = RateCalculateUtils.divWithPrecision(this.successCount - this.pendingCount, this.caseTotal, 2);
}
public void calculateAllNumber(TestPlanStatisticsResponse childResponse) {
this.functionalCaseCount += childResponse.getFunctionalCaseCount();
this.apiCaseCount += childResponse.getApiCaseCount();
this.apiScenarioCount += childResponse.getApiScenarioCount();
this.successCount += childResponse.getSuccessCount();
this.errorCount += childResponse.getErrorCount();
this.fakeErrorCount += childResponse.getFakeErrorCount();
this.blockCount += childResponse.getBlockCount();
this.pendingCount += childResponse.getPendingCount();
}
} }

View File

@ -1,6 +1,5 @@
package io.metersphere.plan.mapper; package io.metersphere.plan.mapper;
import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.api.dto.definition.ApiDefinitionDTO; import io.metersphere.api.dto.definition.ApiDefinitionDTO;
import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO; import io.metersphere.functional.dto.FunctionalCaseModuleCountDTO;
import io.metersphere.functional.dto.ProjectOptionDTO; import io.metersphere.functional.dto.ProjectOptionDTO;
@ -8,6 +7,7 @@ import io.metersphere.plan.domain.TestPlanApiCase;
import io.metersphere.plan.dto.ApiCaseModuleDTO; import io.metersphere.plan.dto.ApiCaseModuleDTO;
import io.metersphere.plan.dto.ResourceSelectParam; import io.metersphere.plan.dto.ResourceSelectParam;
import io.metersphere.plan.dto.TestPlanCaseRunResultCount; import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
import io.metersphere.plan.dto.request.TestPlanApiCaseBatchRequest; import io.metersphere.plan.dto.request.TestPlanApiCaseBatchRequest;
import io.metersphere.plan.dto.request.TestPlanApiCaseModuleRequest; import io.metersphere.plan.dto.request.TestPlanApiCaseModuleRequest;
import io.metersphere.plan.dto.request.TestPlanApiCaseRequest; import io.metersphere.plan.dto.request.TestPlanApiCaseRequest;
@ -75,4 +75,5 @@ public interface ExtTestPlanApiCaseMapper {
List<TestPlanApiCase> getPlanApiCaseNotDeletedByCollectionIds(@Param("collectionIds") List<String> collectionIds); List<TestPlanApiCase> getPlanApiCaseNotDeletedByCollectionIds(@Param("collectionIds") List<String> collectionIds);
List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId);
} }

View File

@ -717,4 +717,23 @@
WHERE t.test_plan_id = #{request.testPlanId} AND atc.deleted = false WHERE t.test_plan_id = #{request.testPlanId} AND atc.deleted = false
<include refid="queryWhereConditionByBatchQueryRequest"/> <include refid="queryWhereConditionByBatchQueryRequest"/>
</select> </select>
<select id="selectDistinctExecResult" resultType="io.metersphere.plan.dto.TestPlanResourceExecResultDTO">
select distinct resource.test_plan_id AS testPlanId,
CASE
WHEN resource.last_exec_result = 'BLOCKED'
THEN 'COMPLETED'
WHEN resource.last_exec_result = 'FAKE_ERROR'
THEN 'COMPLETED'
WHEN resource.last_exec_result = 'ERROR'
THEN 'COMPLETED'
WHEN resource.last_exec_result = 'SUCCESS'
THEN 'COMPLETED'
ELSE 'PENDING'
END AS execResult,
test_plan.group_id AS testPlanGroupId
from test_plan_api_case resource
INNER JOIN test_plan ON test_plan.id = resource.test_plan_id
where test_plan.project_id = #{projectId}
AND test_plan.status != 'ARCHIVED'
</select>
</mapper> </mapper>

View File

@ -6,6 +6,7 @@ import io.metersphere.plan.domain.TestPlanApiScenario;
import io.metersphere.plan.dto.ApiScenarioModuleDTO; import io.metersphere.plan.dto.ApiScenarioModuleDTO;
import io.metersphere.plan.dto.ResourceSelectParam; import io.metersphere.plan.dto.ResourceSelectParam;
import io.metersphere.plan.dto.TestPlanCaseRunResultCount; import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest; import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
import io.metersphere.plan.dto.request.TestPlanApiScenarioBatchRunRequest; import io.metersphere.plan.dto.request.TestPlanApiScenarioBatchRunRequest;
import io.metersphere.plan.dto.request.TestPlanApiScenarioModuleRequest; import io.metersphere.plan.dto.request.TestPlanApiScenarioModuleRequest;
@ -69,4 +70,6 @@ public interface ExtTestPlanApiScenarioMapper {
List<String> getIdsByReportIdAndCollectionId(@Param("testPlanReportId") String testPlanReportId, @Param("collectionId") String collectionId); List<String> getIdsByReportIdAndCollectionId(@Param("testPlanReportId") String testPlanReportId, @Param("collectionId") String collectionId);
List<TestPlanApiScenario> getPlanScenarioCaseNotDeletedByCollectionIds(@Param("collectionIds") List<String> collectionIds); List<TestPlanApiScenario> getPlanScenarioCaseNotDeletedByCollectionIds(@Param("collectionIds") List<String> collectionIds);
List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId);
} }

View File

@ -485,6 +485,25 @@
</foreach> </foreach>
AND a.deleted = false AND a.deleted = false
</select> </select>
<select id="selectDistinctExecResult" resultType="io.metersphere.plan.dto.TestPlanResourceExecResultDTO">
select distinct resource.test_plan_id AS testPlanId,
CASE
WHEN resource.last_exec_result = 'BLOCKED'
THEN 'COMPLETED'
WHEN resource.last_exec_result = 'FAKE_ERROR'
THEN 'COMPLETED'
WHEN resource.last_exec_result = 'ERROR'
THEN 'COMPLETED'
WHEN resource.last_exec_result = 'SUCCESS'
THEN 'COMPLETED'
ELSE 'PENDING'
END AS execResult,
test_plan.group_id AS testPlanGroupId
from test_plan_api_scenario resource
INNER JOIN test_plan ON test_plan.id = resource.test_plan_id
where test_plan.project_id = #{projectId}
AND test_plan.status != 'ARCHIVED'
</select>
<update id="batchUpdateExecutor"> <update id="batchUpdateExecutor">

View File

@ -6,6 +6,7 @@ import io.metersphere.functional.dto.ProjectOptionDTO;
import io.metersphere.plan.domain.TestPlanFunctionalCase; import io.metersphere.plan.domain.TestPlanFunctionalCase;
import io.metersphere.plan.dto.ResourceSelectParam; import io.metersphere.plan.dto.ResourceSelectParam;
import io.metersphere.plan.dto.TestPlanCaseRunResultCount; import io.metersphere.plan.dto.TestPlanCaseRunResultCount;
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest; import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
import io.metersphere.plan.dto.request.TestPlanCaseModuleRequest; import io.metersphere.plan.dto.request.TestPlanCaseModuleRequest;
import io.metersphere.plan.dto.request.TestPlanCaseRequest; import io.metersphere.plan.dto.request.TestPlanCaseRequest;
@ -67,4 +68,5 @@ public interface ExtTestPlanFunctionalCaseMapper {
List<TestPlanFunctionalCase> getPlanCaseNotDeletedByCollectionIds(@Param("collectionIds") List<String> collectionIds); List<TestPlanFunctionalCase> getPlanCaseNotDeletedByCollectionIds(@Param("collectionIds") List<String> collectionIds);
List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId);
} }

View File

@ -578,4 +578,23 @@
GROUP BY GROUP BY
test_plan_functional_case.test_plan_collection_id test_plan_functional_case.test_plan_collection_id
</select> </select>
<select id="selectDistinctExecResult" resultType="io.metersphere.plan.dto.TestPlanResourceExecResultDTO">
select distinct resource.test_plan_id AS testPlanId,
CASE
WHEN resource.last_exec_result = 'BLOCKED'
THEN 'COMPLETED'
WHEN resource.last_exec_result = 'FAKE_ERROR'
THEN 'COMPLETED'
WHEN resource.last_exec_result = 'ERROR'
THEN 'COMPLETED'
WHEN resource.last_exec_result = 'SUCCESS'
THEN 'COMPLETED'
ELSE 'PENDING'
END AS execResult,
test_plan.group_id AS testPlanGroupId
from test_plan_functional_case resource
INNER JOIN test_plan ON test_plan.id = resource.test_plan_id
where test_plan.project_id = #{projectId}
AND test_plan.status != 'ARCHIVED'
</select>
</mapper> </mapper>

View File

@ -2,6 +2,7 @@ package io.metersphere.plan.mapper;
import io.metersphere.plan.domain.TestPlan; import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.dto.TestPlanExecuteHisDTO; import io.metersphere.plan.dto.TestPlanExecuteHisDTO;
import io.metersphere.plan.dto.TestPlanGroupCountDTO;
import io.metersphere.plan.dto.TestPlanQueryConditions; import io.metersphere.plan.dto.TestPlanQueryConditions;
import io.metersphere.plan.dto.request.TestPlanBatchProcessRequest; import io.metersphere.plan.dto.request.TestPlanBatchProcessRequest;
import io.metersphere.plan.dto.request.TestPlanExecuteHisPageRequest; import io.metersphere.plan.dto.request.TestPlanExecuteHisPageRequest;
@ -66,4 +67,8 @@ public interface ExtTestPlanMapper {
List<TestPlanExecuteHisDTO> listHis(@Param("request")TestPlanExecuteHisPageRequest request); List<TestPlanExecuteHisDTO> listHis(@Param("request")TestPlanExecuteHisPageRequest request);
List<String> selectGroupIdByKeyword(@Param("projectId") String projectId, @Param("keyword") String keyword); List<String> selectGroupIdByKeyword(@Param("projectId") String projectId, @Param("keyword") String keyword);
List<TestPlanGroupCountDTO> countByGroupPlan(String projectId);
List<String> selectIdByProjectIdAndWithoutList(@Param("projectId") String projectId, @Param("withoutList") List<String> withoutList);
} }

View File

@ -106,6 +106,13 @@
</if> </if>
) )
</if> </if>
<if test="request.innerIds != null and request.innerIds.size() > 0">
and t.id in
<foreach collection="request.innerIds" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</if>
<choose> <choose>
<when test='request.searchMode == "AND"'> <when test='request.searchMode == "AND"'>
AND <include refid="queryCombine"/> AND <include refid="queryCombine"/>
@ -483,6 +490,27 @@
or t.tags like concat('%', #{keyword}, '%') or t.tags like concat('%', #{keyword}, '%')
) )
</select> </select>
<select id="countByGroupPlan" resultType="io.metersphere.plan.dto.TestPlanGroupCountDTO">
SELECT group_id AS groupId, count(id) AS count
FROM test_plan
WHERE project_id = #{0}
AND status != 'ARCHIVED'
AND group_id != 'NONE'
GROUP BY group_id;
</select>
<select id="selectIdByProjectIdAndWithoutList" resultType="java.lang.String">
SELECT id
FROM test_plan
WHERE project_id = #{projectId}
AND status != 'ARCHIVED'
AND group_id = 'NONE'
<if test="withoutList != null and withoutList.size() != ''">
AND id not in
<foreach collection="withoutList" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</if>
</select>
<update id="batchUpdate"> <update id="batchUpdate">
update test_plan update test_plan

View File

@ -118,6 +118,10 @@ public class TestPlanApiCaseService extends TestPlanResourceService {
@Resource @Resource
private ExtApiTestCaseMapper extApiTestCaseMapper; private ExtApiTestCaseMapper extApiTestCaseMapper;
public List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId) {
return extTestPlanApiCaseMapper.selectDistinctExecResult(projectId);
}
@Override @Override
public void deleteBatchByTestPlanId(List<String> testPlanIdList) { public void deleteBatchByTestPlanId(List<String> testPlanIdList) {
TestPlanApiCaseExample example = new TestPlanApiCaseExample(); TestPlanApiCaseExample example = new TestPlanApiCaseExample();

View File

@ -112,6 +112,10 @@ public class TestPlanApiScenarioService extends TestPlanResourceService {
@Resource @Resource
private TestPlanConfigService testPlanConfigService; private TestPlanConfigService testPlanConfigService;
@Override
public List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId) {
return extTestPlanApiScenarioMapper.selectDistinctExecResult(projectId);
}
@Override @Override
public void deleteBatchByTestPlanId(List<String> testPlanIdList) { public void deleteBatchByTestPlanId(List<String> testPlanIdList) {
TestPlanApiScenarioExample example = new TestPlanApiScenarioExample(); TestPlanApiScenarioExample example = new TestPlanApiScenarioExample();

View File

@ -1,8 +1,10 @@
package io.metersphere.plan.service; package io.metersphere.plan.service;
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
import io.metersphere.plan.mapper.ExtTestPlanMapper; import io.metersphere.plan.mapper.ExtTestPlanMapper;
import io.metersphere.plan.mapper.TestPlanMapper; import io.metersphere.plan.mapper.TestPlanMapper;
import io.metersphere.sdk.constants.ModuleConstants; import io.metersphere.sdk.constants.ModuleConstants;
import io.metersphere.sdk.constants.TestPlanConstants;
import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.Translator; import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.TestPlanModuleExample; import io.metersphere.system.domain.TestPlanModuleExample;
@ -12,6 +14,11 @@ 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 java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service @Service
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public class TestPlanBaseUtilsService { public class TestPlanBaseUtilsService {
@ -40,4 +47,64 @@ public class TestPlanBaseUtilsService {
} }
} }
public Map<String, Map<String, List<String>>> parseExecResult(List<TestPlanResourceExecResultDTO> execResults) {
Map<String, Map<String, List<String>>> returnMap = new HashMap<>();
for (TestPlanResourceExecResultDTO execResult : execResults) {
String groupId = execResult.getTestPlanGroupId();
String planId = execResult.getTestPlanId();
Map<String, List<String>> planMap;
if (returnMap.containsKey(groupId)) {
planMap = returnMap.get(groupId);
List<String> resultList;
if (planMap.containsKey(planId)) {
resultList = planMap.get(planId);
} else {
resultList = new ArrayList<>();
}
resultList.add(execResult.getExecResult());
planMap.put(planId, resultList);
} else {
planMap = new HashMap<>();
List<String> resultList = new ArrayList<>();
resultList.add(execResult.getExecResult());
planMap.put(planId, resultList);
}
returnMap.put(groupId, planMap);
}
return returnMap;
}
public String calculateTestPlanStatus(List<String> resultList) {
//同时包含两种状态进行中
if (resultList.size() == 1) {
if (resultList.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED)) {
return TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED;
} else
return TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED;
} else {
return TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY;
}
}
public String calculateStatusByChildren(List<String> childStatus) {
// 首先去重
childStatus = childStatus.stream().distinct().toList();
/*
1:全部都未开始 则为未开始
2:全部都已完成 则为已完成
3:包含进行中 则为进行中
4:未开始+已完成进行中
*/
if (childStatus.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY)) {
return TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY;
} else if (childStatus.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED) && childStatus.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED)) {
return TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY;
} else if (childStatus.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED)) {
return TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED;
} else {
return TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED;
}
}
} }

View File

@ -196,7 +196,7 @@ public class TestPlanBatchOperationService extends TestPlanBaseUtilsService {
testPlan.setPos(testPlanGroupService.getNextOrder(targetId)); testPlan.setPos(testPlanGroupService.getNextOrder(targetId));
testPlan.setActualEndTime(null); testPlan.setActualEndTime(null);
testPlan.setActualStartTime(null); testPlan.setActualStartTime(null);
testPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_PREPARED); testPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_NOT_ARCHIVED);
testPlanMapper.insert(testPlan); testPlanMapper.insert(testPlan);
//测试配置信息 //测试配置信息
@ -286,7 +286,7 @@ public class TestPlanBatchOperationService extends TestPlanBaseUtilsService {
testPlanGroup.setPos(testPlanGroupService.getNextOrder(originalGroup.getGroupId())); testPlanGroup.setPos(testPlanGroupService.getNextOrder(originalGroup.getGroupId()));
testPlanGroup.setActualEndTime(null); testPlanGroup.setActualEndTime(null);
testPlanGroup.setActualStartTime(null); testPlanGroup.setActualStartTime(null);
testPlanGroup.setStatus(TestPlanConstants.TEST_PLAN_STATUS_PREPARED); testPlanGroup.setStatus(TestPlanConstants.TEST_PLAN_STATUS_NOT_ARCHIVED);
testPlanMapper.insert(testPlanGroup); testPlanMapper.insert(testPlanGroup);
//测试配置信息 //测试配置信息

View File

@ -5,6 +5,7 @@ import io.metersphere.bug.mapper.BugRelationCaseMapper;
import io.metersphere.bug.service.BugCommonService; import io.metersphere.bug.service.BugCommonService;
import io.metersphere.plan.dto.TestPlanBugCaseDTO; import io.metersphere.plan.dto.TestPlanBugCaseDTO;
import io.metersphere.plan.dto.TestPlanCollectionDTO; import io.metersphere.plan.dto.TestPlanCollectionDTO;
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
import io.metersphere.plan.dto.request.BaseCollectionAssociateRequest; import io.metersphere.plan.dto.request.BaseCollectionAssociateRequest;
import io.metersphere.plan.dto.request.TestPlanBugPageRequest; import io.metersphere.plan.dto.request.TestPlanBugPageRequest;
import io.metersphere.plan.dto.response.TestPlanBugPageResponse; import io.metersphere.plan.dto.response.TestPlanBugPageResponse;
@ -62,6 +63,11 @@ public class TestPlanBugService extends TestPlanResourceService {
return 0; return 0;
} }
@Override
public List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId) {
return List.of();
}
@Override @Override
public long getNextOrder(String testPlanId) { public long getNextOrder(String testPlanId) {

View File

@ -137,6 +137,10 @@ public class TestPlanFunctionalCaseService extends TestPlanResourceService {
@Resource @Resource
private TestPlanApiScenarioMapper testPlanApiScenarioMapper; private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
@Override
public List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId) {
return extTestPlanFunctionalCaseMapper.selectDistinctExecResult(projectId);
}
@Override @Override
public long copyResource(String originalTestPlanId, String newTestPlanId, Map<String, String> oldCollectionIdToNewCollectionId, String operator, long operatorTime) { public long copyResource(String originalTestPlanId, String newTestPlanId, Map<String, String> oldCollectionIdToNewCollectionId, String operator, long operatorTime) {
List<TestPlanFunctionalCase> copyList = new ArrayList<>(); List<TestPlanFunctionalCase> copyList = new ArrayList<>();

View File

@ -5,6 +5,8 @@ import com.github.pagehelper.PageHelper;
import io.metersphere.plan.constants.TestPlanResourceConfig; import io.metersphere.plan.constants.TestPlanResourceConfig;
import io.metersphere.plan.domain.TestPlan; import io.metersphere.plan.domain.TestPlan;
import io.metersphere.plan.domain.TestPlanExample; import io.metersphere.plan.domain.TestPlanExample;
import io.metersphere.plan.dto.TestPlanGroupCountDTO;
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
import io.metersphere.plan.dto.request.TestPlanTableRequest; import io.metersphere.plan.dto.request.TestPlanTableRequest;
import io.metersphere.plan.dto.response.TestPlanResponse; import io.metersphere.plan.dto.response.TestPlanResponse;
import io.metersphere.plan.mapper.ExtTestPlanMapper; import io.metersphere.plan.mapper.ExtTestPlanMapper;
@ -23,6 +25,8 @@ import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils; import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -43,6 +47,8 @@ public class TestPlanManagementService {
@Resource @Resource
private TestPlanStatisticsService testPlanStatisticsService; private TestPlanStatisticsService testPlanStatisticsService;
@Resource @Resource
private TestPlanBaseUtilsService testPlanBaseUtilsService;
@Resource
private TestPlanMapper testPlanMapper; private TestPlanMapper testPlanMapper;
public Map<String, Long> moduleCount(TestPlanTableRequest request) { public Map<String, Long> moduleCount(TestPlanTableRequest request) {
@ -69,12 +75,13 @@ public class TestPlanManagementService {
return PageUtils.setPageInfo(page, this.list(request)); return PageUtils.setPageInfo(page, this.list(request));
} }
@Autowired
private ApplicationContext applicationContext;
private void initDefaultFilter(TestPlanTableRequest request) { private void initDefaultFilter(TestPlanTableRequest request) {
if (request.getFilter() == null || !request.getFilter().containsKey("status")) {
List<String> defaultStatusList = new ArrayList<>(); List<String> defaultStatusList = new ArrayList<>();
defaultStatusList.add(TestPlanConstants.TEST_PLAN_STATUS_PREPARED); defaultStatusList.add(TestPlanConstants.TEST_PLAN_STATUS_NOT_ARCHIVED);
defaultStatusList.add(TestPlanConstants.TEST_PLAN_STATUS_UNDERWAY); if (request.getFilter() == null || !request.getFilter().containsKey("status")) {
defaultStatusList.add(TestPlanConstants.TEST_PLAN_STATUS_COMPLETED);
if (request.getFilter() == null) { if (request.getFilter() == null) {
request.setFilter(new HashMap<>() {{ request.setFilter(new HashMap<>() {{
this.put("status", defaultStatusList); this.put("status", defaultStatusList);
@ -82,6 +89,76 @@ public class TestPlanManagementService {
} else { } else {
request.getFilter().put("status", defaultStatusList); request.getFilter().put("status", defaultStatusList);
} }
} else if (!request.getFilter().get("status").contains(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED)) {
List<String> statusList = request.getFilter().get("status");
request.getFilter().put("status", defaultStatusList);
if (statusList.size() < 3) {
List<String> innerIdList = new ArrayList<>();
// 条件过滤
Map<String, TestPlanResourceService> beansOfType = applicationContext.getBeansOfType(TestPlanResourceService.class);
// 将当前项目下未归档的测试计划结果查询出来进行下列符合条件的筛选
List<TestPlanResourceExecResultDTO> execResults = new ArrayList<>();
beansOfType.forEach((k, v) -> execResults.addAll(v.selectDistinctExecResult(request.getProjectId())));
Map<String, Map<String, List<String>>> testPlanExecMap = testPlanBaseUtilsService.parseExecResult(execResults);
Map<String, Long> groupCountMap = extTestPlanMapper.countByGroupPlan(request.getProjectId())
.stream().collect(Collectors.toMap(TestPlanGroupCountDTO::getGroupId, TestPlanGroupCountDTO::getCount));
List<String> completedTestPlanIds = new ArrayList<>();
List<String> preparedTestPlanIds = new ArrayList<>();
List<String> underwayTestPlanIds = new ArrayList<>();
testPlanExecMap.forEach((groupId, planMap) -> {
if (StringUtils.equalsIgnoreCase(groupId, TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) {
planMap.forEach((planId, resultList) -> {
String result = testPlanBaseUtilsService.calculateTestPlanStatus(resultList);
if (StringUtils.equals(result, TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED)) {
completedTestPlanIds.add(planId);
} else if (StringUtils.equals(result, TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY)) {
underwayTestPlanIds.add(planId);
} else if (StringUtils.equals(result, TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED)) {
preparedTestPlanIds.add(planId);
}
});
} else {
long itemPlanCount = groupCountMap.getOrDefault(groupId, 0L);
List<String> itemStatusList = new ArrayList<>();
if (itemPlanCount > planMap.size()) {
// 存在未执行或者没有用例的测试计划 此时这种测试计划的状态为未开始
itemStatusList.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED);
}
planMap.forEach((planId, resultList) -> {
itemStatusList.add(testPlanBaseUtilsService.calculateTestPlanStatus(resultList));
});
String groupStatus = testPlanBaseUtilsService.calculateStatusByChildren(itemStatusList);
if (StringUtils.equals(groupStatus, TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED)) {
completedTestPlanIds.add(groupId);
} else if (StringUtils.equals(groupStatus, TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY)) {
underwayTestPlanIds.add(groupId);
} else if (StringUtils.equals(groupStatus, TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED)) {
preparedTestPlanIds.add(groupId);
}
}
});
testPlanExecMap = null;
if (statusList.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED)) {
// 已完成
innerIdList.addAll(completedTestPlanIds);
}
if (statusList.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY)) {
// 进行中
innerIdList.addAll(underwayTestPlanIds);
}
if (statusList.contains(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED)) {
// 未开始 有一些测试计划/计划组没有用例 / 测试计划 在上面的计算中无法过滤所以用排除法机型处理
List<String> withoutList = new ArrayList<>();
withoutList.addAll(completedTestPlanIds);
withoutList.addAll(underwayTestPlanIds);
innerIdList.addAll(extTestPlanMapper.selectIdByProjectIdAndWithoutList(request.getProjectId(), withoutList));
withoutList = null;
}
request.setInnerIds(innerIdList);
}
} }
if (StringUtils.isNotBlank(request.getKeyword())) { if (StringUtils.isNotBlank(request.getKeyword())) {

View File

@ -5,6 +5,7 @@ import io.metersphere.plan.domain.TestPlanCollectionExample;
import io.metersphere.plan.dto.ModuleSelectDTO; import io.metersphere.plan.dto.ModuleSelectDTO;
import io.metersphere.plan.dto.TestPlanCollectionDTO; import io.metersphere.plan.dto.TestPlanCollectionDTO;
import io.metersphere.plan.dto.TestPlanResourceAssociationParam; import io.metersphere.plan.dto.TestPlanResourceAssociationParam;
import io.metersphere.plan.dto.TestPlanResourceExecResultDTO;
import io.metersphere.plan.dto.request.BaseCollectionAssociateRequest; import io.metersphere.plan.dto.request.BaseCollectionAssociateRequest;
import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest; import io.metersphere.plan.dto.request.BasePlanCaseBatchRequest;
import io.metersphere.plan.dto.response.TestPlanAssociationResponse; import io.metersphere.plan.dto.response.TestPlanAssociationResponse;
@ -65,6 +66,7 @@ public abstract class TestPlanResourceService extends TestPlanSortService {
public abstract long copyResource(String originalTestPlanId, String newTestPlanId, Map<String, String> oldCollectionIdToNewCollectionId, String operator, long operatorTime); public abstract long copyResource(String originalTestPlanId, String newTestPlanId, Map<String, String> oldCollectionIdToNewCollectionId, String operator, long operatorTime);
public abstract List<TestPlanResourceExecResultDTO> selectDistinctExecResult(String projectId);
/** /**
* 关联用例 * 关联用例
* *
@ -124,6 +126,4 @@ public abstract class TestPlanResourceService extends TestPlanSortService {
AssociateCaseDTO associateCaseDTO = new AssociateCaseDTO(excludeIds, selectIds, moduleIds); AssociateCaseDTO associateCaseDTO = new AssociateCaseDTO(excludeIds, selectIds, moduleIds);
return associateCaseDTO; return associateCaseDTO;
} }
} }

View File

@ -134,7 +134,7 @@ public class TestPlanSendNoticeService {
public TestPlanDTO sendAddNotice(TestPlanCreateRequest request) { public TestPlanDTO sendAddNotice(TestPlanCreateRequest request) {
TestPlanDTO dto = new TestPlanDTO(); TestPlanDTO dto = new TestPlanDTO();
BeanUtils.copyBean(dto, request); BeanUtils.copyBean(dto, request);
dto.setStatus(TestPlanConstants.TEST_PLAN_STATUS_PREPARED); dto.setStatus(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED);
return dto; return dto;
} }

View File

@ -6,6 +6,7 @@ import io.metersphere.plan.dto.TestPlanExecuteHisDTO;
import io.metersphere.plan.dto.request.*; import io.metersphere.plan.dto.request.*;
import io.metersphere.plan.dto.response.TestPlanDetailResponse; import io.metersphere.plan.dto.response.TestPlanDetailResponse;
import io.metersphere.plan.dto.response.TestPlanOperationResponse; import io.metersphere.plan.dto.response.TestPlanOperationResponse;
import io.metersphere.plan.dto.response.TestPlanStatisticsResponse;
import io.metersphere.plan.enums.ExecuteMethod; import io.metersphere.plan.enums.ExecuteMethod;
import io.metersphere.plan.job.TestPlanScheduleJob; import io.metersphere.plan.job.TestPlanScheduleJob;
import io.metersphere.plan.mapper.*; import io.metersphere.plan.mapper.*;
@ -102,7 +103,7 @@ public class TestPlanService extends TestPlanBaseUtilsService {
private static final int MAX_TAG_SIZE = 10; private static final int MAX_TAG_SIZE = 10;
@Autowired @Resource
private TestPlanReportService testPlanReportService; private TestPlanReportService testPlanReportService;
/** /**
@ -151,7 +152,7 @@ public class TestPlanService extends TestPlanBaseUtilsService {
createTestPlan.setUpdateUser(operator); createTestPlan.setUpdateUser(operator);
createTestPlan.setCreateTime(operateTime); createTestPlan.setCreateTime(operateTime);
createTestPlan.setUpdateTime(operateTime); createTestPlan.setUpdateTime(operateTime);
createTestPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_PREPARED); createTestPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_NOT_ARCHIVED);
TestPlanConfig testPlanConfig = new TestPlanConfig(); TestPlanConfig testPlanConfig = new TestPlanConfig();
testPlanConfig.setTestPlanId(createTestPlan.getId()); testPlanConfig.setTestPlanId(createTestPlan.getId());
@ -395,18 +396,20 @@ public class TestPlanService extends TestPlanBaseUtilsService {
/** /**
* 测试计划归档 * 测试计划归档
*
* @param id
* @param userId
*/ */
public void archived(String id, String userId) { public void archived(String id, String userId) {
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(id); TestPlan testPlan = testPlanMapper.selectByPrimaryKey(id);
if (StringUtils.equalsAnyIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) { if (StringUtils.equalsAnyIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) {
//判断当前计划组下是否都已完成 (由于算法原因只需要校验当前测试计划组即可
if (!this.isTestPlanCompleted(id)) {
throw new MSException(Translator.get("test_plan.group.not_plan"));
}
//测试计划组归档 //测试计划组归档
updateGroupStatus(testPlan.getId(), userId); updateCompletedGroupStatus(testPlan.getId(), userId);
//关闭定时任务 //关闭定时任务
this.deleteScheduleConfig(testPlan.getId()); this.deleteScheduleConfig(testPlan.getId());
} else if (StringUtils.equals(testPlan.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_COMPLETED) && StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) { } else if (this.isTestPlanCompleted(id) && StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) {
//测试计划 //测试计划
testPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED); testPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED);
testPlan.setUpdateUser(userId); testPlan.setUpdateUser(userId);
@ -417,7 +420,37 @@ public class TestPlanService extends TestPlanBaseUtilsService {
} else { } else {
throw new MSException(Translator.get("test_plan.cannot.archived")); throw new MSException(Translator.get("test_plan.cannot.archived"));
} }
}
/**
* 测试计划归档
*/
public boolean archived(TestPlan testPlan, String userId) {
if (!this.isTestPlanCompleted(testPlan.getId())) {
return false;
}
if (StringUtils.equalsAnyIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)) {
//测试计划组归档
updateCompletedGroupStatus(testPlan.getId(), userId);
//关闭定时任务
this.deleteScheduleConfig(testPlan.getId());
return true;
} else if (StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) {
//测试计划
testPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED);
testPlan.setUpdateUser(userId);
testPlan.setUpdateTime(System.currentTimeMillis());
testPlanMapper.updateByPrimaryKeySelective(testPlan);
//关闭定时任务
this.deleteScheduleConfig(testPlan.getId());
return true;
}
return false;
}
public boolean isTestPlanCompleted(String testPlanId) {
TestPlanStatisticsResponse statisticsResponse = testPlanStatisticsService.calculateRate(Collections.singletonList(testPlanId)).getFirst();
return StringUtils.equalsIgnoreCase(statisticsResponse.getStatus(), TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED);
} }
/** /**
@ -430,14 +463,20 @@ public class TestPlanService extends TestPlanBaseUtilsService {
List<String> batchArchivedIds = request.getSelectIds(); List<String> batchArchivedIds = request.getSelectIds();
if (CollectionUtils.isNotEmpty(batchArchivedIds)) { if (CollectionUtils.isNotEmpty(batchArchivedIds)) {
TestPlanExample example = new TestPlanExample(); TestPlanExample example = new TestPlanExample();
example.createCriteria().andIdIn(batchArchivedIds); example.createCriteria().andIdIn(batchArchivedIds).andStatusNotEqualTo(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED);
List<TestPlan> archivedPlanList = testPlanMapper.selectByExample(example).stream().filter( List<TestPlan> testPlanList = testPlanMapper.selectByExample(example).stream().filter(
testPlan -> StringUtils.equalsAnyIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP) testPlan -> StringUtils.equalsAnyIgnoreCase(testPlan.getType(), TestPlanConstants.TEST_PLAN_TYPE_GROUP)
|| (StringUtils.equals(testPlan.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_COMPLETED) && StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID)) || (StringUtils.equalsIgnoreCase(testPlan.getGroupId(), TestPlanConstants.TEST_PLAN_DEFAULT_GROUP_ID))
).collect(Collectors.toList()); ).toList();
archivedPlanList.forEach(item -> this.archived(item.getId(), currentUser)); List<TestPlan> archivedPlanGroupList = new ArrayList<>();
testPlanList.forEach(item -> {
boolean result = this.archived(item, currentUser);
if (result) {
archivedPlanGroupList.add(item);
}
});
//日志 //日志
testPlanLogService.saveBatchLog(archivedPlanList, currentUser, "/test-plan/batch-archived", HttpMethodConstants.POST.name(), OperationLogType.ARCHIVED.name(), "archive"); testPlanLogService.saveBatchLog(archivedPlanGroupList, currentUser, "/test-plan/batch-archived", HttpMethodConstants.POST.name(), OperationLogType.ARCHIVED.name(), "archive");
} }
} }
@ -447,17 +486,14 @@ public class TestPlanService extends TestPlanBaseUtilsService {
* @param id * @param id
* @param userId * @param userId
*/ */
private void updateGroupStatus(String id, String userId) { private void updateCompletedGroupStatus(String id, String userId) {
TestPlanExample example = new TestPlanExample(); TestPlanExample example = new TestPlanExample();
example.createCriteria().andGroupIdEqualTo(id); example.createCriteria().andGroupIdEqualTo(id);
List<TestPlan> testPlanList = testPlanMapper.selectByExample(example); List<TestPlan> testPlanList = testPlanMapper.selectByExample(example);
if (CollectionUtils.isEmpty(testPlanList)) { if (CollectionUtils.isEmpty(testPlanList)) {
throw new MSException(Translator.get("test_plan.group.not_plan")); throw new MSException(Translator.get("test_plan.group.not_plan"));
} }
List<String> ids = testPlanList.stream().filter(item -> StringUtils.equalsIgnoreCase(item.getStatus(), TestPlanConstants.TEST_PLAN_STATUS_COMPLETED)).map(TestPlan::getId).collect(Collectors.toList()); List<String> ids = testPlanList.stream().map(TestPlan::getId).collect(Collectors.toList());
if (CollectionUtils.isEmpty(ids)) {
throw new MSException(Translator.get("test_plan.group.not_plan"));
}
ids.add(id); ids.add(id);
extTestPlanMapper.batchUpdateStatus(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED, userId, System.currentTimeMillis(), ids); extTestPlanMapper.batchUpdateStatus(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED, userId, System.currentTimeMillis(), ids);
} }
@ -772,37 +808,6 @@ public class TestPlanService extends TestPlanBaseUtilsService {
} }
} }
// private void updateTestPlanStatus(String testPlanId) {
// Map<String, Long> caseExecResultCount = new HashMap<>();
// Map<String, TestPlanResourceService> beansOfType = applicationContext.getBeansOfType(TestPlanResourceService.class);
// beansOfType.forEach((k, v) -> {
// Map<String, Long> map = v.caseExecResultCount(testPlanId);
// map.forEach((key, value) -> {
// if (value != 0) {
// caseExecResultCount.merge(key, value, Long::sum);
// }
// });
// });
//
// String testPlanFinalStatus = TestPlanConstants.TEST_PLAN_STATUS_UNDERWAY;
// if (MapUtils.isEmpty(caseExecResultCount)) {
// // 没有任何执行结果 状态是未开始
// testPlanFinalStatus = TestPlanConstants.TEST_PLAN_STATUS_PREPARED;
// extTestPlanMapper.clearActualEndTime(testPlanId);
// } else if (caseExecResultCount.size() == 1 && caseExecResultCount.containsKey(ExecStatus.PENDING.name()) && caseExecResultCount.get(ExecStatus.PENDING.name()) > 0) {
// // 执行结果只有未开始 状态是未开始
// testPlanFinalStatus = TestPlanConstants.TEST_PLAN_STATUS_PREPARED;
// extTestPlanMapper.clearActualEndTime(testPlanId);
// } else if (!caseExecResultCount.containsKey(ExecStatus.PENDING.name())) {
// // 执行结果没有未开始 已完成
// testPlanFinalStatus = TestPlanConstants.TEST_PLAN_STATUS_COMPLETED;
// extTestPlanMapper.setActualEndTime(testPlanId, System.currentTimeMillis());
// }
//
// this.updateTestPlanStatusAndGroupStatus(testPlanId, testPlanFinalStatus);
// }
public TestPlanOperationResponse sort(PosRequest request, LogInsertModule logInsertModule) { public TestPlanOperationResponse sort(PosRequest request, LogInsertModule logInsertModule) {
testPlanGroupService.sort(request); testPlanGroupService.sort(request);
testPlanLogService.saveMoveLog(testPlanMapper.selectByPrimaryKey(request.getMoveId()), request.getMoveId(), logInsertModule); testPlanLogService.saveMoveLog(testPlanMapper.selectByPrimaryKey(request.getMoveId()), request.getMoveId(), logInsertModule);

View File

@ -4,7 +4,6 @@ import io.metersphere.plan.domain.*;
import io.metersphere.plan.dto.response.TestPlanBugPageResponse; import io.metersphere.plan.dto.response.TestPlanBugPageResponse;
import io.metersphere.plan.dto.response.TestPlanStatisticsResponse; import io.metersphere.plan.dto.response.TestPlanStatisticsResponse;
import io.metersphere.plan.mapper.*; import io.metersphere.plan.mapper.*;
import io.metersphere.plan.utils.RateCalculateUtils;
import io.metersphere.sdk.constants.ExecStatus; import io.metersphere.sdk.constants.ExecStatus;
import io.metersphere.sdk.constants.ResultStatus; import io.metersphere.sdk.constants.ResultStatus;
import io.metersphere.sdk.constants.ScheduleResourceType; import io.metersphere.sdk.constants.ScheduleResourceType;
@ -16,6 +15,7 @@ import io.metersphere.system.mapper.ScheduleMapper;
import io.metersphere.system.utils.ScheduleUtils; import io.metersphere.system.utils.ScheduleUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.*; import java.util.*;
@ -41,6 +41,8 @@ public class TestPlanStatisticsService {
private ExtTestPlanBugMapper extTestPlanBugMapper; private ExtTestPlanBugMapper extTestPlanBugMapper;
@Resource @Resource
private ScheduleMapper scheduleMapper; private ScheduleMapper scheduleMapper;
@Resource
private TestPlanBaseUtilsService testPlanBaseUtilsService;
/** /**
* 计划/计划组的用例统计数据 * 计划/计划组的用例统计数据
@ -71,74 +73,144 @@ public class TestPlanStatisticsService {
}); });
} }
/** private Map<String, TestPlanConfig> selectConfig(List<String> testPlanIds) {
* 计划/计划组的{通过率, 执行进度}统计数据
*
* @param planIds 计划ID集合
*/
public List<TestPlanStatisticsResponse> calculateRate(List<String> planIds) {
// 查出子计划
TestPlanExample testPlanExample = new TestPlanExample();
testPlanExample.createCriteria().andGroupIdIn(planIds);
List<TestPlan> childrenPlan = testPlanMapper.selectByExample(testPlanExample);
childrenPlan.forEach(item -> planIds.add(item.getId()));
List<TestPlanStatisticsResponse> planStatisticsResponses = new ArrayList<>();
/*
* 1. 查询计划下的用例数据集合
* 2. 根据执行结果统计(结果小数保留两位)
*/
// 计划的更多配置
TestPlanConfigExample example = new TestPlanConfigExample(); TestPlanConfigExample example = new TestPlanConfigExample();
example.createCriteria().andTestPlanIdIn(planIds); example.createCriteria().andTestPlanIdIn(testPlanIds);
List<TestPlanConfig> testPlanConfigList = testPlanConfigMapper.selectByExample(example); List<TestPlanConfig> testPlanConfigList = testPlanConfigMapper.selectByExample(example);
Map<String, TestPlanConfig> planConfigMap = testPlanConfigList.stream().collect(Collectors.toMap(TestPlanConfig::getTestPlanId, p -> p)); return testPlanConfigList.stream().collect(Collectors.toMap(TestPlanConfig::getTestPlanId, p -> p));
// 关联的用例数据 }
Map<String, List<TestPlanFunctionalCase>> planFunctionalCaseMap = getFunctionalCaseMapByPlanIds(planIds);
Map<String, List<TestPlanApiCase>> planApiCaseMap = getApiCaseMapByPlanIds(planIds);
Map<String, List<TestPlanApiScenario>> planApiScenarioMap = getApiScenarioByPlanIds(planIds);
//查询定时任务 private Map<String, Schedule> selectSchedule(List<String> testPlanIds) {
ScheduleExample scheduleExample = new ScheduleExample(); ScheduleExample scheduleExample = new ScheduleExample();
scheduleExample.createCriteria().andResourceIdIn(planIds).andResourceTypeEqualTo(ScheduleResourceType.TEST_PLAN.name()); scheduleExample.createCriteria().andResourceIdIn(testPlanIds).andResourceTypeEqualTo(ScheduleResourceType.TEST_PLAN.name());
List<Schedule> schedules = scheduleMapper.selectByExample(scheduleExample); List<Schedule> schedules = scheduleMapper.selectByExample(scheduleExample);
Map<String, Schedule> scheduleMap = schedules.stream().collect(Collectors.toMap(Schedule::getResourceId, t -> t)); return schedules.stream().collect(Collectors.toMap(Schedule::getResourceId, t -> t));
}
planIds.forEach(planId -> { /**
* 计划/计划组的{通过率, 执行进度, 状态}统计数据
*
*/
public List<TestPlanStatisticsResponse> calculateRate(List<String> paramIds) {
// 查出所有计划
TestPlanExample testPlanExample = new TestPlanExample();
testPlanExample.createCriteria().andIdIn(paramIds);
List<TestPlan> paramTestPlanList = testPlanMapper.selectByExample(testPlanExample);
testPlanExample.clear();
testPlanExample.createCriteria().andGroupIdIn(paramIds);
List<TestPlan> childrenTestPlan = testPlanMapper.selectByExample(testPlanExample);
paramTestPlanList.removeAll(childrenTestPlan);
List<String> allTestPlanIdList = new ArrayList<>();
allTestPlanIdList.addAll(paramTestPlanList.stream().map(TestPlan::getId).toList());
allTestPlanIdList.addAll(childrenTestPlan.stream().map(TestPlan::getId).toList());
Map<TestPlan, List<TestPlan>> groupTestPlanMap = new HashMap<>();
for (TestPlan testPlan : paramTestPlanList) {
List<TestPlan> children = new ArrayList<>();
for (TestPlan child : childrenTestPlan) {
if (StringUtils.equalsIgnoreCase(child.getGroupId(), testPlan.getId())) {
children.add(child);
}
}
groupTestPlanMap.put(testPlan, children);
childrenTestPlan.removeAll(children);
}
childrenTestPlan = null;
paramTestPlanList = null;
List<TestPlanStatisticsResponse> returnResponse = new ArrayList<>();
// 计划的更多配置
Map<String, TestPlanConfig> planConfigMap = this.selectConfig(allTestPlanIdList);
// 关联的用例数据
Map<String, List<TestPlanFunctionalCase>> planFunctionalCaseMap = getFunctionalCaseMapByPlanIds(allTestPlanIdList);
Map<String, List<TestPlanApiCase>> planApiCaseMap = getApiCaseMapByPlanIds(allTestPlanIdList);
Map<String, List<TestPlanApiScenario>> planApiScenarioMap = getApiScenarioByPlanIds(allTestPlanIdList);
//查询定时任务
Map<String, Schedule> scheduleMap = this.selectSchedule(allTestPlanIdList);
groupTestPlanMap.forEach((rootPlan, children) -> {
TestPlanStatisticsResponse rootResponse = this.genTestPlanStatisticsResponse(rootPlan, planConfigMap, planFunctionalCaseMap, planApiCaseMap, planApiScenarioMap, scheduleMap);
List<TestPlanStatisticsResponse> childrenResponse = new ArrayList<>();
if (!CollectionUtils.isEmpty(children)) {
List<String> childStatus = new ArrayList<>();
children.forEach(child -> {
TestPlanStatisticsResponse childResponse = this.genTestPlanStatisticsResponse(child, planConfigMap, planFunctionalCaseMap, planApiCaseMap, planApiScenarioMap, scheduleMap);
childResponse.calculateStatus();
childStatus.add(childResponse.getStatus());
//添加到rootResponse中
rootResponse.calculateAllNumber(childResponse);
childrenResponse.add(childResponse);
});
rootResponse.calculateCaseTotal();
rootResponse.calculatePassRate();
rootResponse.calculateExecuteRate();
rootResponse.setStatus(testPlanBaseUtilsService.calculateStatusByChildren(childStatus));
} else {
rootResponse.calculateCaseTotal();
rootResponse.calculatePassRate();
rootResponse.calculateExecuteRate();
rootResponse.calculateStatus();
}
returnResponse.add(rootResponse);
returnResponse.addAll(childrenResponse);
});
return returnResponse;
}
private Map<String, Long> countApiScenarioExecResultMap(List<TestPlanApiScenario> apiScenarios) {
return CollectionUtils.isEmpty(apiScenarios) ? new HashMap<>(16) : apiScenarios.stream().collect(
Collectors.groupingBy(apiScenario -> Optional.ofNullable(apiScenario.getLastExecResult()).orElse(ExecStatus.PENDING.name()), Collectors.counting()));
}
private Map<String, Long> countApiTestCaseExecResultMap(List<TestPlanApiCase> apiCases) {
return CollectionUtils.isEmpty(apiCases) ? new HashMap<>(16) : apiCases.stream().collect(
Collectors.groupingBy(apiCase -> Optional.ofNullable(apiCase.getLastExecResult()).orElse(ExecStatus.PENDING.name()), Collectors.counting()));
}
private Map<String, Long> countFunctionalCaseExecResultMap(List<TestPlanFunctionalCase> functionalCases) {
return CollectionUtils.isEmpty(functionalCases) ? new HashMap<>(16) : functionalCases.stream().collect(
Collectors.groupingBy(functionalCase -> Optional.ofNullable(functionalCase.getLastExecResult()).orElse(ExecStatus.PENDING.name()), Collectors.counting()));
}
private TestPlanStatisticsResponse genTestPlanStatisticsResponse(TestPlan child,
Map<String, TestPlanConfig> planConfigMap,
Map<String, List<TestPlanFunctionalCase>> planFunctionalCaseMap,
Map<String, List<TestPlanApiCase>> planApiCaseMap,
Map<String, List<TestPlanApiScenario>> planApiScenarioMap,
Map<String, Schedule> scheduleMap) {
String planId = child.getId();
TestPlanStatisticsResponse statisticsResponse = new TestPlanStatisticsResponse(); TestPlanStatisticsResponse statisticsResponse = new TestPlanStatisticsResponse();
statisticsResponse.setId(planId); statisticsResponse.setId(planId);
// 测试计划组没有测试计划配置同理也不用参与用例等数据的计算 // 测试计划组没有测试计划配置同理也不用参与用例等数据的计算
if (planConfigMap.containsKey(planId)) { if (planConfigMap.containsKey(planId)) {
statisticsResponse.setPassThreshold(planConfigMap.get(planId).getPassThreshold()); statisticsResponse.setPassThreshold(planConfigMap.get(planId).getPassThreshold());
// 功能用例分组统计开始 (为空时, 默认为未执行)
List<TestPlanFunctionalCase> functionalCases = planFunctionalCaseMap.get(planId); List<TestPlanFunctionalCase> functionalCases = planFunctionalCaseMap.get(planId);
statisticsResponse.setFunctionalCaseCount(CollectionUtils.isNotEmpty(functionalCases) ? functionalCases.size() : 0);
Map<String, Long> functionalCaseResultCountMap = CollectionUtils.isEmpty(functionalCases) ? new HashMap<>(16) : functionalCases.stream().collect(
Collectors.groupingBy(functionalCase -> Optional.ofNullable(functionalCase.getLastExecResult()).orElse(ExecStatus.PENDING.name()), Collectors.counting()));
// 接口用例分组统计开始 (为空时, 默认为未执行)
List<TestPlanApiCase> apiCases = planApiCaseMap.get(planId); List<TestPlanApiCase> apiCases = planApiCaseMap.get(planId);
statisticsResponse.setApiCaseCount(CollectionUtils.isNotEmpty(apiCases) ? apiCases.size() : 0);
Map<String, Long> apiCaseResultCountMap = CollectionUtils.isEmpty(apiCases) ? new HashMap<>(16) : apiCases.stream().collect(
Collectors.groupingBy(apiCase -> Optional.ofNullable(apiCase.getLastExecResult()).orElse(ExecStatus.PENDING.name()), Collectors.counting()));
// 接口场景用例分组统计开始 (为空时, 默认为未执行)
List<TestPlanApiScenario> apiScenarios = planApiScenarioMap.get(planId); List<TestPlanApiScenario> apiScenarios = planApiScenarioMap.get(planId);
statisticsResponse.setApiScenarioCount(CollectionUtils.isNotEmpty(apiScenarios) ? apiScenarios.size() : 0);
Map<String, Long> apiScenarioResultCountMap = CollectionUtils.isEmpty(apiScenarios) ? new HashMap<>(16) : apiScenarios.stream().collect(
Collectors.groupingBy(apiScenario -> Optional.ofNullable(apiScenario.getLastExecResult()).orElse(ExecStatus.PENDING.name()), Collectors.counting())); // 功能用例分组统计开始 (为空时, 默认为未执行)
Map<String, Long> functionalCaseResultCountMap = this.countFunctionalCaseExecResultMap(functionalCases);
// 接口用例分组统计开始 (为空时, 默认为未执行)
Map<String, Long> apiCaseResultCountMap = this.countApiTestCaseExecResultMap(apiCases);
// 接口场景用例分组统计开始 (为空时, 默认为未执行)
Map<String, Long> apiScenarioResultCountMap = this.countApiScenarioExecResultMap(apiScenarios);
// 用例数据汇总 // 用例数据汇总
statisticsResponse.setFunctionalCaseCount(CollectionUtils.isNotEmpty(functionalCases) ? functionalCases.size() : 0);
statisticsResponse.setApiCaseCount(CollectionUtils.isNotEmpty(apiCases) ? apiCases.size() : 0);
statisticsResponse.setApiScenarioCount(CollectionUtils.isNotEmpty(apiScenarios) ? apiScenarios.size() : 0);
statisticsResponse.setSuccessCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.SUCCESS.name())); statisticsResponse.setSuccessCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.SUCCESS.name()));
statisticsResponse.setErrorCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.ERROR.name())); statisticsResponse.setErrorCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.ERROR.name()));
statisticsResponse.setFakeErrorCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.FAKE_ERROR.name())); statisticsResponse.setFakeErrorCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.FAKE_ERROR.name()));
statisticsResponse.setBlockCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.BLOCKED.name())); statisticsResponse.setBlockCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ResultStatus.BLOCKED.name()));
statisticsResponse.setPendingCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ExecStatus.PENDING.name())); statisticsResponse.setPendingCount(countCaseMap(functionalCaseResultCountMap, apiCaseResultCountMap, apiScenarioResultCountMap, ExecStatus.PENDING.name()));
statisticsResponse.setCaseTotal(statisticsResponse.getFunctionalCaseCount() + statisticsResponse.getApiCaseCount() + statisticsResponse.getApiScenarioCount()); statisticsResponse.calculateCaseTotal();
// 通过率 {通过用例数/总用例数} && 执行进度 {非未执行的用例数/总用例数} statisticsResponse.calculatePassRate();
statisticsResponse.setPassRate(RateCalculateUtils.divWithPrecision(statisticsResponse.getSuccessCount(), statisticsResponse.getCaseTotal(), 2)); statisticsResponse.calculateExecuteRate();
statisticsResponse.setExecuteRate(RateCalculateUtils.divWithPrecision(statisticsResponse.getCaseTotal() - statisticsResponse.getPendingCount(), statisticsResponse.getCaseTotal(), 2));
} }
planStatisticsResponses.add(statisticsResponse);
//定时任务 //定时任务
if (scheduleMap.containsKey(planId)) { if (scheduleMap.containsKey(planId)) {
Schedule schedule = scheduleMap.get(planId); Schedule schedule = scheduleMap.get(planId);
@ -154,9 +226,7 @@ public class TestPlanStatisticsService {
statisticsResponse.setNextTriggerTime(ScheduleUtils.getNextTriggerTime(schedule.getValue())); statisticsResponse.setNextTriggerTime(ScheduleUtils.getNextTriggerTime(schedule.getValue()));
} }
} }
return statisticsResponse;
});
return planStatisticsResponses;
} }

View File

@ -20,7 +20,7 @@ public class RateCalculateUtils {
* @param precision 精度 * @param precision 精度
* @return rate * @return rate
*/ */
public static Double divWithPrecision(Integer molecular, Integer denominator, Integer precision) { public static Double divWithPrecision(Long molecular, Long denominator, Integer precision) {
DecimalFormat rateFormat = new DecimalFormat("#.##"); DecimalFormat rateFormat = new DecimalFormat("#.##");
rateFormat.setMinimumFractionDigits(precision); rateFormat.setMinimumFractionDigits(precision);
rateFormat.setMaximumFractionDigits(precision); rateFormat.setMaximumFractionDigits(precision);
@ -38,4 +38,8 @@ public class RateCalculateUtils {
} }
return rate; return rate;
} }
public static Double divWithPrecision(Integer molecular, Integer denominator, Integer precision) {
return divWithPrecision((long) molecular, (long) denominator, precision);
}
} }

View File

@ -3,11 +3,9 @@ package io.metersphere.plan.controller;
import io.metersphere.api.domain.ApiScenario; import io.metersphere.api.domain.ApiScenario;
import io.metersphere.api.domain.ApiTestCase; import io.metersphere.api.domain.ApiTestCase;
import io.metersphere.functional.domain.FunctionalCase; import io.metersphere.functional.domain.FunctionalCase;
import io.metersphere.functional.mapper.FunctionalCaseMapper;
import io.metersphere.plan.constants.TestPlanResourceConfig; import io.metersphere.plan.constants.TestPlanResourceConfig;
import io.metersphere.plan.domain.TestPlan; import io.metersphere.plan.domain.*;
import io.metersphere.plan.domain.TestPlanConfig;
import io.metersphere.plan.domain.TestPlanExample;
import io.metersphere.plan.domain.TestPlanReport;
import io.metersphere.plan.dto.request.*; import io.metersphere.plan.dto.request.*;
import io.metersphere.plan.dto.response.TestPlanOperationResponse; import io.metersphere.plan.dto.response.TestPlanOperationResponse;
import io.metersphere.plan.dto.response.TestPlanResponse; import io.metersphere.plan.dto.response.TestPlanResponse;
@ -21,10 +19,7 @@ import io.metersphere.plan.utils.TestPlanTestUtils;
import io.metersphere.project.domain.Project; import io.metersphere.project.domain.Project;
import io.metersphere.project.dto.filemanagement.request.FileModuleCreateRequest; import io.metersphere.project.dto.filemanagement.request.FileModuleCreateRequest;
import io.metersphere.project.dto.filemanagement.request.FileModuleUpdateRequest; import io.metersphere.project.dto.filemanagement.request.FileModuleUpdateRequest;
import io.metersphere.sdk.constants.ModuleConstants; import io.metersphere.sdk.constants.*;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.constants.TestPlanConstants;
import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.CommonBeanFactory; import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.JSON; import io.metersphere.sdk.util.JSON;
@ -43,6 +38,7 @@ import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.mapper.TestPlanModuleMapper; import io.metersphere.system.mapper.TestPlanModuleMapper;
import io.metersphere.system.service.CommonProjectService; import io.metersphere.system.service.CommonProjectService;
import io.metersphere.system.uid.IDGenerator; import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.uid.NumGenerator;
import io.metersphere.system.utils.CheckLogModel; import io.metersphere.system.utils.CheckLogModel;
import io.metersphere.system.utils.Pager; import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@ -138,9 +134,13 @@ public class TestPlanTests extends BaseTest {
private static final String URL_TEST_PLAN_BATCH_ARCHIVED = "/test-plan/batch-archived"; private static final String URL_TEST_PLAN_BATCH_ARCHIVED = "/test-plan/batch-archived";
private static final String URL_TEST_PLAN_BATCH_EDIT = "/test-plan/batch-edit"; private static final String URL_TEST_PLAN_BATCH_EDIT = "/test-plan/batch-edit";
private static String testPlanId6 = null;
private static String testPlanId16 = null;
private static String groupTestPlanId7 = null; private static String groupTestPlanId7 = null;
private static String groupTestPlanId15 = null; private static String groupTestPlanId15 = null;
private static String groupTestPlanId35 = null; private static String groupTestPlanId35 = null;
private static String groupTestPlanId45 = null;
private static String groupTestPlanId46 = null;
private static List<String> rootPlanIds = new ArrayList<>(); private static List<String> rootPlanIds = new ArrayList<>();
@ -154,6 +154,10 @@ public class TestPlanTests extends BaseTest {
private ExtTestPlanMapper extTestPlanMapper; private ExtTestPlanMapper extTestPlanMapper;
@Resource @Resource
private TestPlanFunctionalCaseMapper testPlanFunctionalCaseMapper; private TestPlanFunctionalCaseMapper testPlanFunctionalCaseMapper;
@Resource
private FunctionalCaseMapper functionalCaseMapper;
private static List<String> functionalCaseId = new ArrayList<>();
@BeforeEach @BeforeEach
public void initTestData() { public void initTestData() {
@ -542,7 +546,7 @@ public class TestPlanTests extends BaseTest {
String moduleId; String moduleId;
if (i < 50) { if (i < 50) {
moduleId = a1Node.getId(); moduleId = a1Node.getId();
if (i == 7 || i == 15 || i == 35) { if (i == 7 || i == 15 || i == 35 || i == 45 || i == 46) {
request.setType(TestPlanConstants.TEST_PLAN_TYPE_GROUP); request.setType(TestPlanConstants.TEST_PLAN_TYPE_GROUP);
} }
a1NodeCount++; a1NodeCount++;
@ -574,13 +578,20 @@ public class TestPlanTests extends BaseTest {
ResultHolder holder = JSON.parseObject(returnStr, ResultHolder.class); ResultHolder holder = JSON.parseObject(returnStr, ResultHolder.class);
String returnId = JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId(); String returnId = JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId();
Assertions.assertNotNull(returnId); Assertions.assertNotNull(returnId);
if (i == 6) {
if (i == 7) { testPlanId6 = returnId;
} else if (i == 7) {
groupTestPlanId7 = returnId; groupTestPlanId7 = returnId;
} else if (i == 15) { } else if (i == 15) {
groupTestPlanId15 = returnId; groupTestPlanId15 = returnId;
} else if (i == 16) {
testPlanId16 = returnId;
} else if (i == 35) { } else if (i == 35) {
groupTestPlanId35 = returnId; groupTestPlanId35 = returnId;
} else if (i == 45) {
groupTestPlanId45 = returnId;
} else if (i == 46) {
groupTestPlanId46 = returnId;
} else if (i > 700 && i < 725) { } else if (i > 700 && i < 725) {
// 701-749 要创建测试计划报告 每个测试计划创建250个报告 // 701-749 要创建测试计划报告 每个测试计划创建250个报告
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
@ -676,6 +687,32 @@ public class TestPlanTests extends BaseTest {
} }
} }
// testPlanId6关联两条已完成用例
this.associationFuncCase(testPlanId6, true);
// testPlanId16 关联未开始用例
this.associationFuncCase(testPlanId16, false);
//在groupTestPlanId35 groupTestPlanId46下面各创建2条测试计划并关联已完成用例
for (int i = 0; i < 4; i++) {
TestPlanCreateRequest itemRequest = new TestPlanCreateRequest();
itemRequest.setProjectId(project.getId());
itemRequest.setModuleId(a1Node.getId());
if (i > 2) {
itemRequest.setGroupId(groupTestPlanId46);
itemRequest.setName("testPlan_group46_" + i);
} else {
itemRequest.setGroupId(groupTestPlanId35);
itemRequest.setName("testPlan_group35_" + i);
}
itemRequest.setBaseAssociateCaseRequest(associateCaseRequest);
MvcResult mvcResult = this.requestPostWithOkAndReturn(URL_POST_TEST_PLAN_ADD, itemRequest);
String returnStr = mvcResult.getResponse().getContentAsString();
ResultHolder holder = JSON.parseObject(returnStr, ResultHolder.class);
Assertions.assertNotNull(JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId());
String returnId = JSON.parseObject(JSON.toJSONString(holder.getData()), TestPlan.class).getId();
this.associationFuncCase(returnId, true);
}
//校验Group数量 //校验Group数量
List<TestPlan> groupList = JSON.parseArray( List<TestPlan> groupList = JSON.parseArray(
JSON.toJSONString( JSON.toJSONString(
@ -683,7 +720,7 @@ public class TestPlanTests extends BaseTest {
this.requestGetWithOkAndReturn(String.format(URL_POST_TEST_PLAN_GROUP_LIST, project.getId())) this.requestGetWithOkAndReturn(String.format(URL_POST_TEST_PLAN_GROUP_LIST, project.getId()))
.getResponse().getContentAsString(), ResultHolder.class).getData()), .getResponse().getContentAsString(), ResultHolder.class).getData()),
TestPlan.class); TestPlan.class);
Assertions.assertEquals(groupList.size(), 3); Assertions.assertEquals(groupList.size(), 5);
/* /*
反例 反例
@ -717,7 +754,49 @@ public class TestPlanTests extends BaseTest {
this.checkTestPlanSortWithOutGroup(); this.checkTestPlanSortWithOutGroup();
this.checkTestPlanSortInGroup(groupTestPlanId7); this.checkTestPlanSortInGroup(groupTestPlanId7);
this.checkTestPlanMoveToGroup(); this.checkTestPlanMoveToGroup();
this.checkTestPlanGroupArchived(groupTestPlanId7); this.checkTestPlanGroupArchived(groupTestPlanId35);
}
private void associationFuncCase(String testPlanId, boolean isFinish) {
FunctionalCase functionalCase = new FunctionalCase();
functionalCase.setProjectId(project.getId());
functionalCase.setName(String.valueOf(System.currentTimeMillis()));
functionalCase.setId(IDGenerator.nextStr());
functionalCase.setModuleId("root");
functionalCase.setTemplateId("root");
functionalCase.setReviewStatus("PREPARED");
functionalCase.setCaseEditType("STEP");
functionalCase.setPos(4096L);
functionalCase.setVersionId("root");
functionalCase.setRefId(functionalCase.getId());
functionalCase.setLastExecuteResult("PREPARED");
functionalCase.setDeleted(false);
functionalCase.setPublicCase(false);
functionalCase.setLatest(true);
functionalCase.setCreateUser("admin");
functionalCase.setCreateTime(System.currentTimeMillis());
functionalCase.setUpdateTime(System.currentTimeMillis());
functionalCase.setNum(NumGenerator.nextNum(project.getId(), ApplicationNumScope.CASE_MANAGEMENT));
functionalCaseMapper.insert(functionalCase);
functionalCaseId.add(functionalCase.getId());
TestPlanFunctionalCase testPlanFunctionalCase = new TestPlanFunctionalCase();
testPlanFunctionalCase.setId(IDGenerator.nextStr());
testPlanFunctionalCase.setTestPlanId(testPlanId);
testPlanFunctionalCase.setFunctionalCaseId(functionalCase.getId());
testPlanFunctionalCase.setCreateTime(System.currentTimeMillis());
testPlanFunctionalCase.setCreateUser("admin");
testPlanFunctionalCase.setPos(4096L);
testPlanFunctionalCase.setLastExecResult("SUCCESS");
testPlanFunctionalCase.setTestPlanCollectionId("root");
testPlanFunctionalCaseMapper.insert(testPlanFunctionalCase);
if (!isFinish) {
testPlanFunctionalCase.setId(IDGenerator.nextStr());
testPlanFunctionalCase.setPos(8192L);
testPlanFunctionalCase.setLastExecResult("PENDING");
testPlanFunctionalCaseMapper.insert(testPlanFunctionalCase);
}
} }
private List<TestPlanResponse> selectByGroupId(String groupId) throws Exception { private List<TestPlanResponse> selectByGroupId(String groupId) throws Exception {
@ -912,16 +991,16 @@ public class TestPlanTests extends BaseTest {
//判断组归档 //判断组归档
TestPlan updatePlan = new TestPlan(); TestPlan updatePlan = new TestPlan();
updatePlan.setId(groupTestPlanId35); updatePlan.setId(groupTestPlanId45);
updatePlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED); updatePlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED);
testPlanMapper.updateByPrimaryKeySelective(updatePlan); testPlanMapper.updateByPrimaryKeySelective(updatePlan);
this.requestPost(URL_TEST_PLAN_BATCH_MOVE, request).andExpect(status().is5xxServerError()); this.requestPost(URL_TEST_PLAN_BATCH_MOVE, request).andExpect(status().is5xxServerError());
//改回来 //改回来
updatePlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_PREPARED); updatePlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_NOT_ARCHIVED);
testPlanMapper.updateByPrimaryKeySelective(updatePlan); testPlanMapper.updateByPrimaryKeySelective(updatePlan);
//正式测试 //正式测试
groupId = groupTestPlanId35; groupId = groupTestPlanId45;
request.setTargetId(groupId); request.setTargetId(groupId);
this.requestPostWithOkAndReturn(URL_TEST_PLAN_BATCH_MOVE, request); this.requestPostWithOkAndReturn(URL_TEST_PLAN_BATCH_MOVE, request);
List<TestPlanResponse> groups = this.selectByGroupId(groupId); List<TestPlanResponse> groups = this.selectByGroupId(groupId);
@ -950,20 +1029,21 @@ public class TestPlanTests extends BaseTest {
// 测试计划组内的测试计划不能归档 // 测试计划组内的测试计划不能归档
List<TestPlanResponse> testPlanResponseList = this.selectByGroupId(groupId); List<TestPlanResponse> testPlanResponseList = this.selectByGroupId(groupId);
TestPlanResponse cannotArchivedPlan = testPlanResponseList.getFirst(); TestPlanResponse cannotArchivedPlan = testPlanResponseList.getFirst();
testPlanMapper.updateByPrimaryKeySelective(new TestPlan() {{
this.setId(cannotArchivedPlan.getId());
this.setStatus(TestPlanConstants.TEST_PLAN_STATUS_COMPLETED);
}});
this.requestGet(String.format(URL_TEST_PLAN_ARCHIVED, cannotArchivedPlan.getId())).andExpect(status().is5xxServerError()); this.requestGet(String.format(URL_TEST_PLAN_ARCHIVED, cannotArchivedPlan.getId())).andExpect(status().is5xxServerError());
//归档测试组内的测试计划 //归档测试组内的测试计划
for (TestPlanResponse testPlanResponse : testPlanResponseList) {
testPlanMapper.updateByPrimaryKeySelective(new TestPlan() {{
this.setId(testPlanResponse.getId());
this.setStatus(TestPlanConstants.TEST_PLAN_STATUS_COMPLETED);
}});
}
this.requestGetWithOk(String.format(URL_TEST_PLAN_ARCHIVED, groupId)); this.requestGetWithOk(String.format(URL_TEST_PLAN_ARCHIVED, groupId));
//归档不能归档的测试计划
this.requestGet(String.format(URL_TEST_PLAN_ARCHIVED, rootPlanIds.getFirst())).andExpect(status().is5xxServerError());
//归档普通测试计划
this.requestGetWithOk(String.format(URL_TEST_PLAN_ARCHIVED, testPlanId6));
// testPlan6更改回去
TestPlan testPlan = new TestPlan();
testPlan.setId(testPlanId6);
testPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_NOT_ARCHIVED);
testPlanMapper.updateByPrimaryKeySelective(testPlan);
} }
@ -1003,11 +1083,104 @@ public class TestPlanTests extends BaseTest {
TestPlanTableRequest groupRequest = new TestPlanTableRequest(); TestPlanTableRequest groupRequest = new TestPlanTableRequest();
//查询游离态测试计划 //查询游离态测试计划
TestPlanTableRequest onlyPlanRequest = new TestPlanTableRequest(); TestPlanTableRequest onlyPlanRequest = new TestPlanTableRequest();
// 状态过滤的测试计划
TestPlanTableRequest statusRequest = new TestPlanTableRequest();
BeanUtils.copyBean(groupRequest, dataRequest); BeanUtils.copyBean(groupRequest, dataRequest);
BeanUtils.copyBean(onlyPlanRequest, dataRequest); BeanUtils.copyBean(onlyPlanRequest, dataRequest);
BeanUtils.copyBean(statusRequest, dataRequest);
groupRequest.setType(TestPlanConstants.TEST_PLAN_TYPE_GROUP); groupRequest.setType(TestPlanConstants.TEST_PLAN_TYPE_GROUP);
onlyPlanRequest.setType(TestPlanConstants.TEST_PLAN_TYPE_PLAN); onlyPlanRequest.setType(TestPlanConstants.TEST_PLAN_TYPE_PLAN);
//进行状态筛选 -- 空状态
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
dataRequest.getCurrent(),
dataRequest.getPageSize(),
999 - 1);
/*
现有数据状态
已完成的 6 47
进行中的 16
已归档的 35
*/
//进行状态筛选 -- 未开始
statusRequest.setFilter(new HashMap<>() {{
this.put("status", Collections.singletonList(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED));
}});
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
dataRequest.getCurrent(),
dataRequest.getPageSize(),
999 - 1 - 1 - 2);
//进行状态筛选 -- 已完成
statusRequest.setFilter(new HashMap<>() {{
this.put("status", Collections.singletonList(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED));
}});
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
dataRequest.getCurrent(),
dataRequest.getPageSize(),
2);
//进行状态筛选 -- 进行中
statusRequest.setFilter(new HashMap<>() {{
this.put("status", Collections.singletonList(TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY));
}});
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
dataRequest.getCurrent(),
dataRequest.getPageSize(),
1);
//进行状态筛选 -- 已完成和未开始
statusRequest.setFilter(new HashMap<>() {{
this.put("status", new ArrayList<String>() {{
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED);
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED);
}});
}});
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
dataRequest.getCurrent(),
dataRequest.getPageSize(),
999 - 1 - 1);
//进行状态筛选 -- 已完成和进行中
statusRequest.setFilter(new HashMap<>() {{
this.put("status", new ArrayList<String>() {{
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED);
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY);
}});
}});
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
dataRequest.getCurrent(),
dataRequest.getPageSize(),
3);
//进行状态筛选 -- 进行中和未开始
statusRequest.setFilter(new HashMap<>() {{
this.put("status", new ArrayList<String>() {{
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY);
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED);
}});
}});
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
dataRequest.getCurrent(),
dataRequest.getPageSize(),
999 - 1 - 2);
//进行状态筛选 -- 已完成未开始进行中
statusRequest.setFilter(new HashMap<>() {{
this.put("status", new ArrayList<String>() {{
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_UNDERWAY);
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_PREPARED);
this.add(TestPlanConstants.TEST_PLAN_SHOW_STATUS_COMPLETED);
}});
}});
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
URL_POST_TEST_PLAN_PAGE, statusRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
dataRequest.getCurrent(),
dataRequest.getPageSize(),
999 - 1);
BaseTreeNode a1Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a1"); BaseTreeNode a1Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a1");
BaseTreeNode a2Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a2"); BaseTreeNode a2Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a2");
BaseTreeNode a3Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a3"); BaseTreeNode a3Node = TestPlanTestUtils.getNodeByName(preliminaryTreeNodes, "a3");
@ -1024,6 +1197,7 @@ public class TestPlanTests extends BaseTest {
dataRequest.getCurrent(), dataRequest.getCurrent(),
dataRequest.getPageSize(), dataRequest.getPageSize(),
999 - 1); 999 - 1);
//查询归档的 //查询归档的
dataRequest.setFilter(new HashMap<>() {{ dataRequest.setFilter(new HashMap<>() {{
this.put("status", Collections.singletonList(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED)); this.put("status", Collections.singletonList(TestPlanConstants.TEST_PLAN_STATUS_ARCHIVED));
@ -1038,13 +1212,13 @@ public class TestPlanTests extends BaseTest {
URL_POST_TEST_PLAN_PAGE, groupRequest).getResponse().getContentAsString(StandardCharsets.UTF_8), URL_POST_TEST_PLAN_PAGE, groupRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
dataRequest.getCurrent(), dataRequest.getCurrent(),
dataRequest.getPageSize(), dataRequest.getPageSize(),
3 - 1); 5 - 1);
//只查询计划 //只查询计划
testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn( testPlanTestService.checkTestPlanPage(this.requestPostWithOkAndReturn(
URL_POST_TEST_PLAN_PAGE, onlyPlanRequest).getResponse().getContentAsString(StandardCharsets.UTF_8), URL_POST_TEST_PLAN_PAGE, onlyPlanRequest).getResponse().getContentAsString(StandardCharsets.UTF_8),
dataRequest.getCurrent(), dataRequest.getCurrent(),
dataRequest.getPageSize(), dataRequest.getPageSize(),
996); 999 - 5);
//按照名称倒叙 //按照名称倒叙
dataRequest.setSort(new HashMap<>() {{ dataRequest.setSort(new HashMap<>() {{
@ -1243,17 +1417,17 @@ public class TestPlanTests extends BaseTest {
//修改a2节点下的数据91,92的所属测试计划组 //修改a2节点下的数据91,92的所属测试计划组
updateRequest = testPlanTestService.generateUpdateRequest(testPlanTestService.selectTestPlanByName("testPlan_91").getId()); updateRequest = testPlanTestService.generateUpdateRequest(testPlanTestService.selectTestPlanByName("testPlan_91").getId());
updateRequest.setGroupId(groupTestPlanId35); updateRequest.setGroupId(groupTestPlanId45);
this.requestPostWithOk(URL_POST_TEST_PLAN_UPDATE, updateRequest); this.requestPostWithOk(URL_POST_TEST_PLAN_UPDATE, updateRequest);
a2NodeCount--; a2NodeCount--;
updateRequest = testPlanTestService.generateUpdateRequest(testPlanTestService.selectTestPlanByName("testPlan_92").getId()); updateRequest = testPlanTestService.generateUpdateRequest(testPlanTestService.selectTestPlanByName("testPlan_92").getId());
updateRequest.setGroupId(groupTestPlanId35); updateRequest.setGroupId(groupTestPlanId45);
this.requestPostWithOk(URL_POST_TEST_PLAN_UPDATE, updateRequest); this.requestPostWithOk(URL_POST_TEST_PLAN_UPDATE, updateRequest);
a2NodeCount--; a2NodeCount--;
TestPlan updatePlan = new TestPlan(); TestPlan updatePlan = new TestPlan();
updatePlan.setId(groupTestPlanId7); updatePlan.setId(groupTestPlanId7);
updatePlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_UNDERWAY); updatePlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_NOT_ARCHIVED);
testPlanMapper.updateByPrimaryKeySelective(updatePlan); testPlanMapper.updateByPrimaryKeySelective(updatePlan);
//修改测试计划组信息 //修改测试计划组信息
updateRequest = testPlanTestService.generateUpdateRequest(groupTestPlanId7); updateRequest = testPlanTestService.generateUpdateRequest(groupTestPlanId7);
@ -2113,25 +2287,15 @@ public class TestPlanTests extends BaseTest {
public void testArchived() throws Exception { public void testArchived() throws Exception {
//计划 -- 首先状态不是已完成 //计划 -- 首先状态不是已完成
this.requestGet(String.format(URL_TEST_PLAN_ARCHIVED, "wx_test_plan_id_1")).andExpect(status().is5xxServerError()); this.requestGet(String.format(URL_TEST_PLAN_ARCHIVED, "wx_test_plan_id_1")).andExpect(status().is5xxServerError());
//更改状态再归档
TestPlan testPlan = new TestPlan();
testPlan.setId("wx_test_plan_id_1");
testPlan.setStatus(TestPlanConstants.TEST_PLAN_STATUS_COMPLETED);
testPlanMapper.updateByPrimaryKeySelective(testPlan);
this.requestGetWithOk(String.format(URL_TEST_PLAN_ARCHIVED, "wx_test_plan_id_1"));
//计划组没有可归档的测试计划 //计划组没有可归档的测试计划
this.requestGet(String.format(URL_TEST_PLAN_ARCHIVED, "wx_test_plan_id_2")).andExpect(status().is5xxServerError()); this.requestGet(String.format(URL_TEST_PLAN_ARCHIVED, "wx_test_plan_id_2")).andExpect(status().is5xxServerError());
this.requestGetWithOk(String.format(URL_TEST_PLAN_ARCHIVED, "wx_test_plan_id_5"));
} }
@Test @Test
@Order(303) @Order(303)
public void testCopy() throws Exception { public void testCopy() throws Exception {
// 1. 已归档的不能再归档计划 无用例 // 1. 已归档的不能再归档计划 无用例
requestGet(String.format(URL_TEST_PLAN_COPY, "wx_test_plan_id_1")).andExpect(status().is5xxServerError()); requestGet(String.format(URL_TEST_PLAN_COPY, groupTestPlanId35)).andExpect(status().is5xxServerError());
// 2.计划 有用例 // 2.计划 有用例
MvcResult mvcResult1 = this.requestGetWithOkAndReturn(String.format(URL_TEST_PLAN_COPY, "wx_test_plan_id_4")); MvcResult mvcResult1 = this.requestGetWithOkAndReturn(String.format(URL_TEST_PLAN_COPY, "wx_test_plan_id_4"));