fix(UI 自动化): ui报告统计,查询相关问题

--bug=1015192 --user=张大海 【测试跟踪】ui用例统计分析,步骤数统计的不对 https://www.tapd.cn/55049933/s/1212920

--bug=1015062 --user=张大海 【测试跟踪】测试计划执行UI场景,没执行的场景显示了之前执行的结果 https://www.tapd.cn/55049933/s/1212922

--bug=1015059 --user=张大海 【测试跟踪】测试计划报告,UI场景结果显示在了接口场景结果里 https://www.tapd.cn/55049933/s/1212924

--bug=1015057 --user=张大海 【测试跟踪】UI测试计划报告,最新的报告内容会覆盖之前的 https://www.tapd.cn/55049933/s/1212926
This commit is contained in:
zhangdahai112 2022-07-27 00:41:34 +08:00 committed by f2c-ci-robot[bot]
parent 86bac64869
commit 9978b43c7b
10 changed files with 128 additions and 42 deletions

View File

@ -3,18 +3,25 @@ package io.metersphere.api.service;
import io.metersphere.api.dto.automation.RunScenarioRequest;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.dto.RunUiScenarioRequest;
import io.metersphere.dto.UiScenarioDTO;
import io.metersphere.dto.UiScenarioRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.lang.reflect.Method;
import java.util.List;
import java.util.function.Function;
@Service
@Transactional(rollbackFor = Exception.class)
public class UiAutomationServiceProxy {
public Object run(RunScenarioRequest request) {
return invoke((clazz) -> {
private Object invoke(Function<Class, Method> getDeclaredMethod, Object... args) {
return CommonBeanFactory.invoke("uiAutomationService", getDeclaredMethod, args);
}
public List run(RunScenarioRequest request) {
return (List) invoke((clazz) -> {
try {
return clazz.getDeclaredMethod("run", RunUiScenarioRequest.class);
} catch (NoSuchMethodException e) {
@ -24,8 +31,14 @@ public class UiAutomationServiceProxy {
}, request);
}
private Object invoke(Function<Class, Method> getDeclaredMethod, Object... args) {
return CommonBeanFactory.invoke("uiAutomationService", getDeclaredMethod, args);
public List<UiScenarioDTO> list(UiScenarioRequest request) {
return (List<UiScenarioDTO>) invoke((clazz) -> {
try {
return clazz.getDeclaredMethod("list", UiScenarioRequest.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
return null;
}
}, request);
}
}

View File

@ -57,5 +57,7 @@ public class TestPlanReportContentWithBLOBs extends TestPlanReportContent implem
private String apiBaseCount;
private String uiAllCases;
private static final long serialVersionUID = 1L;
}

View File

@ -36,6 +36,7 @@
<result column="plan_ui_scenario_report_struct" jdbcType="LONGVARCHAR" property="planUiScenarioReportStruct" />
<result column="ui_result" jdbcType="LONGVARCHAR" property="uiResult" />
<result column="api_base_count" jdbcType="LONGVARCHAR" property="apiBaseCount" />
<result column="ui_all_cases" jdbcType="LONGVARCHAR" property="uiAllCases" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
@ -104,7 +105,8 @@
issue_list, api_all_cases, api_failure_cases, scenario_all_cases, scenario_failure_cases,
load_all_Cases, load_failure_cases, plan_scenario_report_struct, plan_api_case_report_struct,
plan_load_case_report_struct, error_report_cases, error_report_scenarios, un_execute_cases,
un_execute_scenarios, plan_ui_scenario_report_struct, ui_result, api_base_count
un_execute_scenarios, plan_ui_scenario_report_struct, ui_result, api_base_count,
ui_all_cases
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.TestPlanReportContentExample" resultMap="ResultMapWithBLOBs">
select
@ -167,7 +169,8 @@
plan_load_case_report_struct, error_report_cases,
error_report_scenarios, un_execute_cases,
un_execute_scenarios, plan_ui_scenario_report_struct,
ui_result, api_base_count)
ui_result, api_base_count, ui_all_cases
)
values (#{id,jdbcType=VARCHAR}, #{testPlanReportId,jdbcType=VARCHAR}, #{startTime,jdbcType=BIGINT},
#{caseCount,jdbcType=BIGINT}, #{endTime,jdbcType=BIGINT}, #{executeRate,jdbcType=DOUBLE},
#{passRate,jdbcType=DOUBLE}, #{isThirdPartIssue,jdbcType=BIT}, #{config,jdbcType=LONGVARCHAR},
@ -180,7 +183,8 @@
#{planLoadCaseReportStruct,jdbcType=LONGVARCHAR}, #{errorReportCases,jdbcType=LONGVARCHAR},
#{errorReportScenarios,jdbcType=LONGVARCHAR}, #{unExecuteCases,jdbcType=LONGVARCHAR},
#{unExecuteScenarios,jdbcType=LONGVARCHAR}, #{planUiScenarioReportStruct,jdbcType=LONGVARCHAR},
#{uiResult,jdbcType=LONGVARCHAR}, #{apiBaseCount,jdbcType=LONGVARCHAR})
#{uiResult,jdbcType=LONGVARCHAR}, #{apiBaseCount,jdbcType=LONGVARCHAR}, #{uiAllCases,jdbcType=LONGVARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestPlanReportContentWithBLOBs">
insert into test_plan_report_content
@ -281,6 +285,9 @@
<if test="apiBaseCount != null">
api_base_count,
</if>
<if test="uiAllCases != null">
ui_all_cases,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -379,6 +386,9 @@
<if test="apiBaseCount != null">
#{apiBaseCount,jdbcType=LONGVARCHAR},
</if>
<if test="uiAllCases != null">
#{uiAllCases,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.TestPlanReportContentExample" resultType="java.lang.Long">
@ -486,6 +496,9 @@
<if test="record.apiBaseCount != null">
api_base_count = #{record.apiBaseCount,jdbcType=LONGVARCHAR},
</if>
<if test="record.uiAllCases != null">
ui_all_cases = #{record.uiAllCases,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -524,7 +537,8 @@
un_execute_scenarios = #{record.unExecuteScenarios,jdbcType=LONGVARCHAR},
plan_ui_scenario_report_struct = #{record.planUiScenarioReportStruct,jdbcType=LONGVARCHAR},
ui_result = #{record.uiResult,jdbcType=LONGVARCHAR},
api_base_count = #{record.apiBaseCount,jdbcType=LONGVARCHAR}
api_base_count = #{record.apiBaseCount,jdbcType=LONGVARCHAR},
ui_all_cases = #{record.uiAllCases,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -639,6 +653,9 @@
<if test="apiBaseCount != null">
api_base_count = #{apiBaseCount,jdbcType=LONGVARCHAR},
</if>
<if test="uiAllCases != null">
ui_all_cases = #{uiAllCases,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
@ -674,7 +691,8 @@
un_execute_scenarios = #{unExecuteScenarios,jdbcType=LONGVARCHAR},
plan_ui_scenario_report_struct = #{planUiScenarioReportStruct,jdbcType=LONGVARCHAR},
ui_result = #{uiResult,jdbcType=LONGVARCHAR},
api_base_count = #{apiBaseCount,jdbcType=LONGVARCHAR}
api_base_count = #{apiBaseCount,jdbcType=LONGVARCHAR},
ui_all_cases = #{uiAllCases,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.TestPlanReportContent">

View File

@ -19,4 +19,5 @@ public class TestPlanExecuteReportDTO {
private Map<String,String> testPlanLoadCaseIdAndReportIdMap;
private Map<String,TestPlanFailureApiDTO> apiCaseInfoDTOMap;
private Map<String,TestPlanFailureScenarioDTO> scenarioInfoDTOMap;
private Map<String,TestPlanUiScenarioDTO> uiScenarioInfoDTOMap;
}

View File

@ -8,8 +8,11 @@ import java.util.List;
@Getter
@Setter
public class TestPlanUiResultReportDTO {
//历史的case数据
private List<TestCaseReportStatusResultDTO> uiScenarioCaseData;
//场景的分类统计数据
private List<TestCaseReportStatusResultDTO> uiScenarioData;
//步骤的分类统计数据
private List<TestCaseReportStatusResultDTO> uiScenarioStepData;
}

View File

@ -669,6 +669,9 @@ public class TestPlanReportService {
if (reportDTO.getUiResult() != null) {
testPlanReportContentWithBLOBs.setUiResult(JSONObject.toJSONString(reportDTO.getUiResult()));
}
if (reportDTO.getUiAllCases() != null) {
testPlanReportContentWithBLOBs.setUiAllCases(JSONObject.toJSONString(reportDTO.getUiAllCases()));
}
if (reportDTO.getLoadResult() != null) {
testPlanReportContentWithBLOBs.setLoadResult(JSONObject.toJSONString(reportDTO.getLoadResult()));
}
@ -973,6 +976,9 @@ public class TestPlanReportService {
if (StringUtils.isNotBlank(testPlanReportContent.getUiResult())) {
testPlanReportDTO.setUiResult(JSONObject.parseObject(testPlanReportContent.getUiResult(), TestPlanUiResultReportDTO.class));
}
if (StringUtils.isNotBlank(testPlanReportContent.getUiAllCases())) {
testPlanReportDTO.setUiAllCases(JSONObject.parseArray(testPlanReportContent.getUiAllCases(), TestPlanUiScenarioDTO.class));
}
testPlanReportDTO.setId(reportId);
TestPlanReport testPlanReport = testPlanReportMapper.selectByPrimaryKey(testPlanReportContent.getTestPlanReportId());
testPlanReportDTO.setName(testPlanReport.getName());
@ -1121,6 +1127,7 @@ public class TestPlanReportService {
Map<String, String> testPlanLoadCaseIdAndReportIdMap = new LinkedHashMap<>();
Map<String, TestPlanFailureApiDTO> apiCaseInfoDTOMap = new LinkedHashMap<>();
Map<String, TestPlanFailureScenarioDTO> scenarioInfoDTOMap = new LinkedHashMap<>();
Map<String, TestPlanUiScenarioDTO> uiScenarioInfoDTOMap = new LinkedHashMap<>();
if (testPlanReportContentWithBLOBs != null) {
if (StringUtils.isNotEmpty(testPlanReportContentWithBLOBs.getPlanApiCaseReportStruct())) {
@ -1160,9 +1167,9 @@ public class TestPlanReportService {
}
}
if (StringUtils.isNotEmpty(testPlanReportContentWithBLOBs.getPlanUiScenarioReportStruct())) {
List<TestPlanFailureScenarioDTO> scenarioInfoDTOList = null;
List<TestPlanUiScenarioDTO> scenarioInfoDTOList = null;
try {
scenarioInfoDTOList = JSONArray.parseArray(testPlanReportContentWithBLOBs.getPlanUiScenarioReportStruct(), TestPlanFailureScenarioDTO.class);
scenarioInfoDTOList = JSONArray.parseArray(testPlanReportContentWithBLOBs.getPlanUiScenarioReportStruct(), TestPlanUiScenarioDTO.class);
} catch (Exception ignored) {
}
if (scenarioInfoDTOList == null) {
@ -1171,9 +1178,10 @@ public class TestPlanReportService {
} catch (Exception ignored) {
}
} else {
for (TestPlanFailureScenarioDTO item : scenarioInfoDTOList) {
for (TestPlanUiScenarioDTO item : scenarioInfoDTOList) {
testPlanUiScenarioIdAndReportIdMap.put(item.getId(), item.getReportId());
scenarioInfoDTOMap.put(item.getId(), item);
uiScenarioInfoDTOMap.put(item.getId(), item);
}
}
}
@ -1184,7 +1192,7 @@ public class TestPlanReportService {
}
}
}
TestPlanExecuteReportDTO returnDTO = new TestPlanExecuteReportDTO(testPlanApiCaseIdAndReportIdMap, testPlanScenarioIdAndReportIdMap, testPlanUiScenarioIdAndReportIdMap, testPlanLoadCaseIdAndReportIdMap, apiCaseInfoDTOMap, scenarioInfoDTOMap);
TestPlanExecuteReportDTO returnDTO = new TestPlanExecuteReportDTO(testPlanApiCaseIdAndReportIdMap, testPlanScenarioIdAndReportIdMap, testPlanUiScenarioIdAndReportIdMap, testPlanLoadCaseIdAndReportIdMap, apiCaseInfoDTOMap, scenarioInfoDTOMap, uiScenarioInfoDTOMap);
return returnDTO;
}

View File

@ -1403,13 +1403,17 @@ public class TestPlanService {
}
}
public void buildUiReport(TestPlanSimpleReportDTO report, JSONObject config, String planId, boolean saveResponse) {
public void buildUiReport(TestPlanSimpleReportDTO report, JSONObject config, String planId, TestPlanExecuteReportDTO testPlanExecuteReportDTO, boolean saveResponse) {
if (checkReportConfig(config, "ui")) {
List<TestPlanUiScenarioDTO> allCases;
List<String> statusList = getUiReportStatusList(config);
if (statusList != null) {
// 不等于null说明配置了用例根据配置的状态查询用例
allCases = testPlanUiScenarioCaseService.getAllCasesByStatusList(planId, statusList);
if (testPlanExecuteReportDTO != null) {
allCases = testPlanUiScenarioCaseService.getAllCases(testPlanExecuteReportDTO.getTestPlanUiScenarioIdAndReportIdMap(), testPlanExecuteReportDTO.getUiScenarioInfoDTOMap());
} else {
allCases = testPlanUiScenarioCaseService.getAllCasesByStatusList(planId, statusList);
}
report.setUiAllCases(allCases);
if (saveResponse) {
buildUiScenarioResponse(allCases);
@ -1839,6 +1843,7 @@ public class TestPlanService {
buildFunctionalReport(report, config, testPlanReport.getTestPlanId());
buildApiReport(report, config, testPlanExecuteReportDTO);
buildLoadReport(report, config, testPlanExecuteReportDTO.getTestPlanLoadCaseIdAndReportIdMap(), false);
buildUiReport(report, config, testPlanReport.getTestPlanId(), testPlanExecuteReportDTO, false);
returnDTO.setTestPlanSimpleReportDTO(report);
return returnDTO;
} else {
@ -1859,7 +1864,7 @@ public class TestPlanService {
buildFunctionalReport(report, config, planId);
buildApiReport(report, config, planId, saveResponse);
buildLoadReport(report, config, planId, saveResponse);
buildUiReport(report, config, planId, saveResponse);
buildUiReport(report, config, planId, null, saveResponse);
return report;
}

View File

@ -5,13 +5,14 @@ import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.EnvironmentType;
import io.metersphere.api.dto.automation.*;
import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.api.dto.automation.ExecuteType;
import io.metersphere.api.dto.automation.RunTestPlanScenarioRequest;
import io.metersphere.api.dto.automation.TestPlanScenarioRequest;
import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.api.service.UiAutomationServiceProxy;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiTestEnvironmentMapper;
import io.metersphere.base.mapper.TestPlanMapper;
import io.metersphere.base.mapper.TestPlanUiScenarioMapper;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtTestPlanUiScenarioCaseMapper;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.ExecuteResult;
@ -26,10 +27,6 @@ import io.metersphere.service.ProjectApplicationService;
import io.metersphere.service.ProjectService;
import io.metersphere.track.dto.*;
import io.metersphere.track.request.testcase.TestPlanScenarioCaseBatchRequest;
import io.metersphere.dto.RunUiScenarioRequest;
import io.metersphere.dto.UiScenarioRequest;
import io.metersphere.track.dto.UiRunModeConfigDTO;
import io.metersphere.xpack.ui.service.UiAutomationService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
@ -49,7 +46,7 @@ import java.util.stream.Collectors;
public class TestPlanUiScenarioCaseService {
@Resource
UiAutomationService uiAutomationService;
UiAutomationServiceProxy uiAutomationServiceProxy;
@Resource
TestPlanUiScenarioMapper testPlanUiScenarioMapper;
@Resource
@ -71,6 +68,8 @@ public class TestPlanUiScenarioCaseService {
private TestPlanService testPlanService;
@Resource
private ProjectApplicationService projectApplicationService;
@Resource
private UiScenarioMapper uiScenarioMapper;
public List<UiScenarioDTO> list(TestPlanScenarioRequest request) {
request.setProjectId(null);
@ -135,7 +134,7 @@ public class TestPlanUiScenarioCaseService {
request.setNotInTestPlan(false);
}
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, uiAutomationService.list(request));
return PageUtils.setPageInfo(page, uiAutomationServiceProxy.list(request));
}
public int delete(String id) {
@ -216,7 +215,7 @@ public class TestPlanUiScenarioCaseService {
request.setUiConfig(configDTO);
request.setPlanCaseIds(planCaseIdList);
request.setRequestOriginator("TEST_PLAN");
return uiAutomationService.run(request);
return uiAutomationServiceProxy.run(request);
}
public void setScenarioEnv(List<TestPlanUiScenario> testPlanApiScenarios, List<String> planScenarioIds, RunModeConfigDTO runModeConfig) {
@ -485,16 +484,34 @@ public class TestPlanUiScenarioCaseService {
private void calculateScenarioResultDTO(PlanReportCaseDTO item,
TestPlanScenarioStepCountDTO stepCount) {
if (StringUtils.isNotBlank(item.getReportId())) {
APIScenarioReportResult apiScenarioReportResult = apiScenarioReportService.get(item.getReportId(),false);
if (apiScenarioReportResult != null) {
String content = apiScenarioReportResult.getContent();
APIScenarioReportResult uiScenarioReportResult = apiScenarioReportService.get(item.getReportId(), false);
if (uiScenarioReportResult != null) {
String content = uiScenarioReportResult.getContent();
if (StringUtils.isNotBlank(content)) {
JSONObject jsonObject = JSONObject.parseObject(content);
stepCount.setScenarioStepTotal(stepCount.getScenarioStepTotal() + jsonObject.getIntValue("scenarioStepTotal"));
stepCount.setScenarioStepSuccess(stepCount.getScenarioStepSuccess() + jsonObject.getIntValue("scenarioStepSuccess"));
stepCount.setScenarioStepError(stepCount.getScenarioStepError() + jsonObject.getIntValue("scenarioStepError"));
stepCount.setScenarioStepErrorReport(stepCount.getScenarioStepErrorReport() + jsonObject.getIntValue("scenarioStepErrorReport"));
stepCount.setScenarioStepUnExecute(stepCount.getScenarioStepUnExecute() + jsonObject.getIntValue("scenarioStepUnExecuteReport"));
if (!StringUtils.equalsIgnoreCase("STOP", uiScenarioReportResult.getStatus())) {
stepCount.setScenarioStepTotal(stepCount.getScenarioStepTotal() + jsonObject.getIntValue("scenarioStepTotal"));
stepCount.setScenarioStepUnExecute(stepCount.getScenarioStepUnExecute() + jsonObject.getIntValue("scenarioStepUnExecuteReport"));
} else {
//串行执行的报告 勾选了失败停止 后续的所有场景的未禁用步骤都统计到总数和未执行里面去
UiScenarioWithBLOBs stoppedScenario = uiScenarioMapper.selectByPrimaryKey(uiScenarioReportResult.getScenarioId());
if (stoppedScenario == null) {
TestPlanUiScenario testPlanUiScenario = testPlanUiScenarioMapper.selectByPrimaryKey(uiScenarioReportResult.getScenarioId());
stoppedScenario = uiScenarioMapper.selectByPrimaryKey(testPlanUiScenario.getUiScenarioId());
}
if (stoppedScenario == null) {
return;
}
int totalSteps = getTotalSteps(stoppedScenario);
stepCount.setScenarioStepTotal(stepCount.getScenarioStepTotal() + totalSteps);
stepCount.setScenarioStepUnExecute(stepCount.getScenarioStepUnExecute() + totalSteps);
}
}
}
} else {
@ -502,6 +519,27 @@ public class TestPlanUiScenarioCaseService {
}
}
/**
* 获取一个ui场景所有未禁用的步骤数
*
* @param stoppedScenario
* @return
*/
private int getTotalSteps(UiScenarioWithBLOBs stoppedScenario) {
if (StringUtils.isNotBlank(stoppedScenario.getScenarioDefinition())) {
JSONObject definition = JSONObject.parseObject(stoppedScenario.getScenarioDefinition());
if (definition.containsKey("hashTree")) {
return definition
.getJSONArray("hashTree")
.stream()
.filter(cmd -> (((JSONObject) cmd).getBoolean("enable")))
.collect(Collectors.toList())
.size();
}
}
return 0;
}
private void getScenarioCaseReportStatusResultDTO(String status, int count, List<TestCaseReportStatusResultDTO> scenarioCaseList) {
if (count > 0) {
TestCaseReportStatusResultDTO scenarioCase = new TestCaseReportStatusResultDTO();
@ -518,7 +556,7 @@ public class TestPlanUiScenarioCaseService {
}
public List<TestPlanUiScenarioDTO> getAllCases(Map<String, String> idMap, Map<String, TestPlanUiScenarioDTO> scenarioInfoDTOMap) {
String defaultStatus = "Fail";
String defaultStatus = "Error";
Map<String, String> reportStatus = apiScenarioReportService.getReportStatusByReportIds(idMap.values());
Map<String, String> savedReportMap = new HashMap<>(idMap);
List<TestPlanUiScenarioDTO> apiTestCases = new ArrayList<>();
@ -530,10 +568,6 @@ public class TestPlanUiScenarioCaseService {
String status = reportStatus.get(reportId);
if (status == null) {
status = defaultStatus;
} else {
if (StringUtils.equalsIgnoreCase(status, "Error")) {
status = "Fail";
}
}
dto.setLastResult(status);
dto.setStatus(status);

View File

@ -253,4 +253,6 @@ CREATE TABLE IF NOT EXISTS `attachment_module_relation`
INDEX `attachment_module_index`(`relation_id`, `relation_type`) USING BTREE
) ENGINE = InnoDB
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci;
COLLATE = utf8mb4_general_ci;
ALTER TABLE test_plan_report_content ADD COLUMN `ui_all_cases` LONGTEXT COMMENT 'ui all cases (JSON format)';

View File

@ -13,7 +13,7 @@
:is-template="isTemplate" :report="report" :plan-id="planId"/>
<test-plan-load-report v-if="loadEnable" :is-db="isDb" :share-id="shareId" :is-share="isShare"
:is-template="isTemplate" :report="report" :plan-id="planId"/>
<test-plan-ui-report v-if="uiEnable" :is-db="false" :share-id="shareId" :is-share="isShare"
<test-plan-ui-report v-if="uiEnable" :is-db="isDb" :share-id="shareId" :is-share="isShare"
:is-template="isTemplate" :report="report" :plan-id="planId"/>
</el-card>
</ms-main-container>