refactor: 功能用例关联测试改成多对多的关系

This commit is contained in:
chenjianxing 2022-01-24 16:48:01 +08:00 committed by 刘瑞斌
parent 8573dc8234
commit e45ff554f1
21 changed files with 125 additions and 105 deletions

View File

@ -41,4 +41,9 @@ public class ApiTestCaseRequest extends BaseQueryRequest {
* 是否需要查询环境字段
*/
private boolean selectEnvironment = false;
/**
* 查询排除一些接口
*/
private List<String> notInIds;
}

View File

@ -146,16 +146,12 @@
atc.num,
atc.priority,
atc.tags,
project_version.id versionId,
project_version.name versionName
atc.version_id
FROM
api_test_case atc
LEFT JOIN test_case_test tct ON atc.id = tct.test_id
INNER JOIN api_definition ad ON ad.id = atc.api_definition_id
INNER JOIN project_version on atc.project_id = project_version.project_id and atc.version_id = project_version.id
WHERE
tct.test_id IS NULL
AND atc. STATUS != 'Trash'
(atc.status is null or atc.status != 'Trash')
<if test="request.protocol != null and request.protocol!=''">
and ad.protocol = #{request.protocol}
</if>
@ -167,6 +163,12 @@
or atc.tags like CONCAT('%', #{request.name},'%')
or atc.num like CONCAT('%', #{request.name},'%'))
</if>
<if test="request.notInIds != null and request.notInIds.size() > 0">
and atc.id not in
<foreach collection="request.notInIds" item="notInId" separator="," open="(" close=")">
#{notInId}
</foreach>
</if>
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
and ad.module_id in
<foreach collection="request.moduleIds" item="nodeId" separator="," open="(" close=")">
@ -396,16 +398,12 @@
atc.step_total,
atc. STATUS,
atc.tags,
project_version.id versionId,
project_version.name versionName
atc.version_id
FROM
api_scenario atc
LEFT JOIN test_case_test tct ON atc.id = tct.test_id
LEFT JOIN project_version ON atc.project_id = project_version.project_id
AND project_version.id = atc.version_id
WHERE
tct.test_id IS NULL
AND atc. STATUS != 'Trash'
(atc.status is null or atc.status != 'Trash')
<if test="request.projectId != null and request.projectId!=''">
and atc.project_id = #{request.projectId}
</if>
@ -414,6 +412,12 @@
or atc.tags like CONCAT('%', #{request.name},'%')
or atc.num like CONCAT('%', #{request.name},'%'))
</if>
<if test="request.notInIds != null and request.notInIds.size() > 0">
and atc.id not in
<foreach collection="request.notInIds" item="notInId" separator="," open="(" close=")">
#{notInId}
</foreach>
</if>
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
and atc.api_scenario_module_id in
<foreach collection="request.moduleIds" item="nodeId" separator="," open="(" close=")">
@ -456,16 +460,12 @@
atc. STATUS,
atc.create_time,
atc.update_time,
project_version.name versionName,
project_version.id versionId
atc.version_id
FROM
load_test atc
LEFT JOIN test_case_test tct ON atc.id = tct.test_id
LEFT JOIN project_version ON atc.project_id = project_version.project_id
AND atc.version_id = project_version.id
WHERE
tct.test_id IS NULL
AND atc. STATUS != 'Trash'
(atc.status is null or atc.status != 'Trash')
<if test="request.projectId != null and request.projectId!=''">
and atc.project_id = #{request.projectId}
</if>
@ -476,6 +476,12 @@
<include refid="queryVersionCondition">
<property name="versionTable" value="atc"/>
</include>
<if test="request.notInIds != null and request.notInIds.size() > 0">
and atc.id not in
<foreach collection="request.notInIds" item="notInId" separator="," open="(" close=")">
#{notInId}
</foreach>
</if>
<if test="request.combine != null">
<include refid="loadCaseCombine">
<property name="condition" value="request.combine"/>

View File

@ -1,12 +1,15 @@
package io.metersphere.commons.utils;
import io.metersphere.api.dto.definition.ApiTestCaseDTO;
import io.metersphere.base.domain.Project;
import io.metersphere.base.domain.ProjectVersion;
import io.metersphere.base.domain.User;
import io.metersphere.commons.exception.MSException;
import io.metersphere.controller.request.BaseQueryRequest;
import io.metersphere.controller.request.OrderRequest;
import io.metersphere.controller.request.ResetOrderRequest;
import io.metersphere.service.ProjectService;
import io.metersphere.service.ProjectVersionService;
import io.metersphere.service.UserService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@ -240,4 +243,37 @@ public class ServiceUtils {
public static String getCopyName(String name) {
return "copy_" + name + "_" + UUID.randomUUID().toString().substring(0, 4);
}
public static void buildVersionInfo(List<? extends Object> list) {
ProjectVersionService projectVersionService = CommonBeanFactory.getBean(ProjectVersionService.class);
List<String> versionIds = list.stream()
.map(i -> {
Class<?> clazz = i.getClass();
try {
Method getVersionId = clazz.getMethod("getVersionId");
return getVersionId.invoke(i).toString();
} catch (Exception e) {
LogUtil.error(e);
return i.toString();
}
})
.distinct()
.collect(Collectors.toList());
Map<String, String> versionNameMap = projectVersionService.getProjectVersionByIds(versionIds).
stream()
.collect(Collectors.toMap(ProjectVersion::getId, ProjectVersion::getName));
list.forEach(i -> {
Class<?> clazz = i.getClass();
try {
Method setVersionName = clazz.getMethod("setVersionName", String.class);
Method getVersionId = clazz.getMethod("getVersionId");
Object versionId = getVersionId.invoke(i);
setVersionName.invoke(i, versionNameMap.get(versionId));
} catch (Exception e) {
LogUtil.error(e);
}
});
}
}

View File

@ -20,4 +20,6 @@ public interface ProjectVersionService {
List<ProjectVersionDTO> getProjectVersions(String projectId);
void changeStatus(String id, String status);
List<ProjectVersion> getProjectVersionByIds(List<String> versionIds);
}

View File

@ -23,4 +23,6 @@ public class LoadCaseRequest extends TestPlanLoadCase {
private String refId;
// 测试计划是否允许重复
private boolean repeatCase;
private List<String> notInIds;
}

View File

@ -2121,7 +2121,21 @@ public class TestCaseService {
}
public List<ApiTestCaseDTO> getTestCaseApiCaseRelateList(ApiTestCaseRequest request) {
return testCaseTestMapper.relevanceApiList(request);
List<ApiTestCaseDTO> apiTestCaseDTOS = testCaseTestMapper.relevanceApiList(request);
ServiceUtils.buildVersionInfo(apiTestCaseDTOS);
return apiTestCaseDTOS;
}
public List<ApiScenarioDTO> getTestCaseScenarioCaseRelateList(ApiScenarioRequest request) {
List<ApiScenarioDTO> apiScenarioDTOS = testCaseTestMapper.relevanceScenarioList(request);
ServiceUtils.buildVersionInfo(apiScenarioDTOS);
return apiScenarioDTOS;
}
public List<LoadTestDTO> getTestCaseLoadCaseRelateList(LoadCaseRequest request) {
List<LoadTestDTO> loadTestDTOS = testCaseTestMapper.relevanceLoadList(request);
ServiceUtils.buildVersionInfo(loadTestDTOS);
return loadTestDTOS;
}
public void relateTest(String type, String caseId, List<String> apiIds) {
@ -2231,14 +2245,6 @@ public class TestCaseService {
return caseIds;
}
public List<ApiScenarioDTO> getTestCaseScenarioCaseRelateList(ApiScenarioRequest request) {
return testCaseTestMapper.relevanceScenarioList(request);
}
public List<LoadTestDTO> getTestCaseLoadCaseRelateList(LoadCaseRequest request) {
return testCaseTestMapper.relevanceLoadList(request);
}
public TestCaseWithBLOBs getTestCaseStep(String testCaseId) {
return extTestCaseMapper.getTestCaseStep(testCaseId);
}

@ -1 +1 @@
Subproject commit 822aeec9210db1933e89410eae111c04b1c81b75
Subproject commit efef7ac19f97c762792969275e1fd80ec1f10c66

View File

@ -21,6 +21,7 @@
:current-protocol="currentProtocol"
:select-node-ids="selectNodeIds"
:project-id="projectId"
:not-in-ids="notInIds"
:versionEnable="versionEnable"
ref="apiCaseList"/>
@ -57,6 +58,10 @@ export default {
versionEnable: {
type: Boolean,
default: false
},
notInIds: {
type: Array,
default: null
}
},
methods: {

View File

@ -8,6 +8,7 @@
<test-case-relate-load-list
:project-id="projectId"
:not-in-ids="notInIds"
:versionEnable="versionEnable"
ref="apiCaseList"/>
@ -47,6 +48,10 @@ export default {
versionEnable: {
type: Boolean,
default: false
},
notInIds: {
type: Array,
default: null
}
},
methods: {

View File

@ -54,17 +54,6 @@
:content="itemName" style="margin-left: 0px; margin-right: 2px"></ms-tag>
</template>
</ms-table-column>
<!-- <ms-table-column-->
<!-- prop="path"-->
<!-- width="180px"-->
<!-- :label="'API'+ $t('api_test.definition.api_path')"/>-->
<!-- <ms-table-column-->
<!-- sortable="custom"-->
<!-- prop="casePath"-->
<!-- width="180px"-->
<!-- :label="$t('api_test.definition.request.case')+ $t('api_test.definition.api_path')"/>-->
</ms-table>
<ms-table-pagination :change="initTable" :current-page.sync="currentPage" :page-size.sync="pageSize"
@ -132,6 +121,10 @@ export default {
versionEnable: {
type: Boolean,
default: false
},
notInIds: {
type: Array,
default: null
}
},
created: function () {
@ -173,6 +166,7 @@ export default {
if (this.currentProtocol != null) {
this.condition.protocol = this.currentProtocol;
}
this.condition.notInIds = this.notInIds; //
let url = '/test/case/relevance/api/list/';
this.result = this.$post(this.buildPagePath(url), this.condition, response => {
this.total = response.data.itemCount;

View File

@ -114,6 +114,10 @@ export default {
props: {
projectId: String,
versionEnable: Boolean,
notInIds: {
type: Array,
default: null
}
},
created: function () {
this.initTable();
@ -141,6 +145,7 @@ export default {
} else if (this.projectId != null) {
this.condition.projectId = this.projectId;
}
this.condition.notInIds = this.notInIds;
let url = '/test/case/relevance/load/list/';
this.result = this.$post(this.buildPagePath(url), this.condition, response => {
this.total = response.data.itemCount;

View File

@ -24,20 +24,6 @@
sortable=true>
</ms-table-column>
<!-- <ms-table-column-->
<!-- v-if="item.id == 'num' && customNum" prop="customNum"-->
<!-- label="ID"-->
<!-- sortable-->
<!-- :fields-width="fieldsWidth"-->
<!-- min-width="120px">-->
<!-- <template slot-scope="scope">-->
<!-- &lt;!&ndash;<span style="cursor:pointer" v-if="isReadOnly"> {{ scope.row.customNum }} </span>&ndash;&gt;-->
<!-- <el-tooltip content="编辑">-->
<!-- <a style="cursor:pointer" @click="edit(scope.row)"> {{ scope.row.customNum }} </a>-->
<!-- </el-tooltip>-->
<!-- </template>-->
<!-- </ms-table-column>-->
<ms-table-column
prop="name"
:label="$t('api_test.automation.scenario_name')"/>
@ -142,6 +128,10 @@ export default {
selectNodeIds: Array,
projectId: String,
versionEnable: Boolean,
notInIds: {
type: Array,
default: null
}
},
created: function () {
this.initTable();
@ -174,6 +164,7 @@ export default {
this.condition.projectId = this.projectId;
}
let url = '/test/case/relevance/scenario/list/';
this.condition.notInIds = this.notInIds;
this.result = this.$post(this.buildPagePath(url), this.condition, response => {
this.total = response.data.itemCount;
this.tableData = response.data.listObject;

View File

@ -20,6 +20,7 @@
<test-case-relate-scenario-list
:select-node-ids="selectNodeIds"
:project-id="projectId"
:not-in-ids="notInIds"
:versionEnable="versionEnable"
ref="apiCaseList"/>
@ -60,6 +61,10 @@ export default {
type: Boolean,
default: false
},
notInIds: {
type: Array,
default: null
}
},
methods: {
open() {

View File

@ -50,17 +50,20 @@
<test-case-api-relate
:case-id="caseId"
:versionEnable="versionEnable"
:not-in-ids="notInIds"
@refresh="initTable"
ref="apiCaseRelevance"/>
<test-case-scenario-relate
:case-id="caseId"
:versionEnable="versionEnable"
:not-in-ids="notInIds"
@refresh="initTable"
ref="apiScenarioRelevance"/>
<test-case-load-relate
:case-id="caseId"
:not-in-ids="notInIds"
:versionEnable="versionEnable"
@refresh="initTable"
ref="loadRelevance"/>
@ -97,6 +100,7 @@ export default {
}
}
],
notInIds: null
}
},
props: ['caseId', 'readOnly', 'versionEnable'],
@ -127,6 +131,7 @@ export default {
initTable() {
this.result = getRelateTest(this.caseId, (data) => {
this.data = data;
this.notInIds = data.map(i => i.testId);
});
},
}

View File

@ -6,7 +6,6 @@
:project-id="getProjectId()"
:condition="condition"
:plan-id="planId"
@changeVersion="changeVersion"
@refresh="initTable"
@relevanceCase="$emit('relevanceCase')"
@setEnvironment="setEnvironment"
@ -647,14 +646,6 @@ export default {
}
});
},
changeVersion(currentVersion) {
if (currentVersion == "") {
this.condition.versionId = null;
} else {
this.condition.versionId = currentVersion;
}
this.initTable();
},
getVersionOptions() {
if (hasLicense()) {
this.$get('/project/version/get-project-versions/' + getCurrentProjectID(), response => {

View File

@ -5,7 +5,6 @@
<test-plan-scenario-list-header
:condition="condition"
:projectId="projectId"
@changeVersion="changeVersion"
@refresh="search"
@relevanceCase="$emit('relevanceCase', 'scenario')"/>
</template>
@ -570,10 +569,6 @@ export default {
});
}
},
changeVersion(currentVersion) {
this.condition.versionId = currentVersion || null;
this.search();
},
getVersionOptions() {
if (hasLicense()) {
this.$get('/project/version/get-project-versions/' + getCurrentProjectID(), response => {

View File

@ -11,7 +11,6 @@
<ms-table-button v-permission="['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL']" icon="el-icon-connection"
:content="$t('test_track.plan_view.relevance_test_case')"
@click="$emit('relevanceCase')"/>
<version-select v-xpack :project-id="projectId" @changeVersion="changeVersion"/>
</template>
</ms-table-header>
@ -21,12 +20,9 @@
import MsTableHeader from "../../../../../common/components/MsTableHeader";
import MsTableButton from "../../../../../common/components/MsTableButton";
import MsEnvironmentSelect from "../../../../../api/definition/components/case/MsEnvironmentSelect";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const VersionSelect = requireComponent.keys().length > 0 ? requireComponent("./version/VersionSelect.vue") : {};
export default {
name: "TestPlanCaseListHeader",
components: {MsEnvironmentSelect, MsTableButton, MsTableHeader, 'VersionSelect': VersionSelect.default},
components: {MsEnvironmentSelect, MsTableButton, MsTableHeader},
props: ['condition', 'projectId', 'isReadOnly', 'planId'],
methods: {
setEnvironment(data) {

View File

@ -11,7 +11,6 @@
<ms-table-button v-permission="['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL']" icon="el-icon-connection"
:content="$t('test_track.plan_view.relevance_test_case')"
@click="$emit('relevanceCase')"/>
<version-select v-xpack :project-id="projectId" @changeVersion="$emit('changeVersion', $event)" margin-left="10"/>
</template>
</ms-table-header>
@ -21,13 +20,11 @@
import MsTableHeader from "../../../../../common/components/MsTableHeader";
import MsTableButton from "../../../../../common/components/MsTableButton";
import MsEnvironmentSelect from "../../../../../api/definition/components/case/MsEnvironmentSelect";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const VersionSelect = requireComponent.keys().length > 0 ? requireComponent("./version/VersionSelect.vue") : {};
export default {
name: "TestPlanScenarioListHeader",
components: {
MsEnvironmentSelect, MsTableButton, MsTableHeader, 'VersionSelect': VersionSelect.default,
MsEnvironmentSelect, MsTableButton, MsTableHeader
},
props: ['condition', 'isReadOnly', 'projectId'],
methods: {}

View File

@ -409,7 +409,6 @@ export default {
selectNodeIds: {
type: Array
},
currentVersion: null,
versionEnable: {
type: Boolean,
default: false
@ -439,10 +438,6 @@ export default {
},
condition() {
this.$emit('setCondition', this.condition);
},
currentVersion(){
this.condition.versionId = this.currentVersion;
this.initTableData();
}
},
created() {

View File

@ -17,16 +17,13 @@
:right-tip="$t('test_track.case.minder')"
:right-content="$t('test_track.case.minder')"
:middle-button-enable="false">
<template v-slot:version>
<version-select v-xpack :project-id="projectId" @changeVersion="changeVersion"/>
</template>
<functional-test-case-list
class="table-list"
v-if="activeDom === 'left'"
@openTestCaseRelevanceDialog="openTestCaseRelevanceDialog"
@refresh="refresh"
@setCondition="setCondition"
:current-version="currentVersion"
:plan-id="planId"
:clickType="clickType"
:select-node-ids="selectNodeIds"
@ -70,7 +67,6 @@ import TestPlanFunctionalRelevance
import IsChangeConfirm from "@/business/components/common/components/IsChangeConfirm";
import {openMinderConfirm, saveMinderConfirm} from "@/business/components/track/common/minder/minderUtils";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const VersionSelect = requireComponent.keys().length > 0 ? requireComponent("./version/VersionSelect.vue") : {};
export default {
name: "TestPlanFunctional",
@ -82,7 +78,6 @@ export default {
FunctionalTestCaseList,
MsTestPlanCommonComponent,
NodeTree,
'VersionSelect': VersionSelect.default,
},
data() {
return {
@ -93,8 +88,7 @@ export default {
selectNode: {},
condition: {},
tmpActiveDom: null,
tmpPath: null,
currentVersion: null,
tmpPath: null
};
},
props: [
@ -185,9 +179,6 @@ export default {
} else {
return true;
}
},
changeVersion(currentVersion) {
this.currentVersion = currentVersion || null;
}
}
};
@ -195,7 +186,4 @@ export default {
</script>
<style scoped>
.version-select {
padding-left: 10px;
}
</style>

View File

@ -5,8 +5,7 @@
<test-plan-load-case-list-header
:condition="condition"
:plan-id="planId"
:isShowVersion="true"
@changeVersion="changeVersion"
:isShowVersion="false"
@refresh="initTable"
@relevanceCase="$emit('relevanceCase')"/>
</template>
@ -469,14 +468,6 @@ export default {
clearInterval(this.refreshScheduler);
}
},
changeVersion(currentVersion) {
if (currentVersion == "") {
this.condition.versionId = null;
} else {
this.condition.versionId = currentVersion;
}
this.initTable();
},
getVersionOptions() {
if (hasLicense()) {
this.$get('/project/version/get-project-versions/' + getCurrentProjectID(), response => {