feat(接口测试): 场景变量支持启用自身场景变量优先策略

--story=1010745 --user=赵勇 场景嵌套引用的变量取值优化-接口场景 https://www.tapd.cn/55049933/s/1312907
This commit is contained in:
fit2-zhao 2022-12-05 15:41:03 +08:00 committed by 刘瑞斌
parent bed8db3a55
commit 0f174ae73e
8 changed files with 105 additions and 15 deletions

View File

@ -29,6 +29,7 @@ import io.metersphere.service.EnvironmentGroupProjectService;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.http.control.Header;
@ -78,6 +79,9 @@ public class MsScenario extends MsTestElement {
@JSONField(ordinal = 30)
private Boolean variableEnable;
@JSONField(ordinal = 31)
private Boolean mixEnable;
private static final String BODY_FILE_DIR = FileUtils.BODY_FILE_DIR;
public MsScenario() {
@ -127,7 +131,8 @@ public class MsScenario extends MsTestElement {
}
}
}
if (CollectionUtils.isNotEmpty(this.getVariables()) && (this.variableEnable == null || this.variableEnable)) {
if (CollectionUtils.isNotEmpty(this.getVariables()) && (this.variableEnable == null || this.variableEnable)) {
config.setVariables(this.variables);
}
HashTree scenarioTree = tree;
@ -144,12 +149,19 @@ public class MsScenario extends MsTestElement {
if (config != null && !config.getExcludeScenarioIds().contains(this.getId())) {
scenarioTree = MsCriticalSectionController.createHashTree(tree, this.getName(), this.isEnable());
}
// 启用当前场景变量优先选择
if ((mixEnable == null || BooleanUtils.isTrue(mixEnable))
&& (this.variableEnable == null || BooleanUtils.isFalse(this.variableEnable))) {
config.margeVariables(this.variables, config.getTransferVariables());
}
// 环境变量
Arguments arguments = arguments(this.isEnvironmentEnable() ? newConfig : config);
if (arguments != null && (this.variableEnable == null || this.variableEnable)) {
if (arguments != null && ((this.variableEnable == null || this.variableEnable)
|| (this.mixEnable == null || this.mixEnable))) {
Arguments valueSupposeMock = ParameterConfig.valueSupposeMock(arguments);
// 这里加入自定义变量解决ForEach循环控制器取值问题循环控制器无法从vars中取值
if (this.variableEnable != null && this.variableEnable) {
if ((this.variableEnable == null || this.variableEnable) || (this.mixEnable == null || this.mixEnable)) {
scenarioTree.add(ElementUtil.argumentsToUserParameters(valueSupposeMock));
} else {
scenarioTree.add(valueSupposeMock);
@ -167,6 +179,7 @@ public class MsScenario extends MsTestElement {
}
}
}
// 添加全局前置
this.setGlobProcessor(this.isEnvironmentEnable() ? newConfig : config, scenarioTree, true);

View File

@ -21,10 +21,12 @@ import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.track.service.TestPlanApiCaseService;
import lombok.Data;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.Arguments;
import java.util.*;
import java.util.stream.Collectors;
@Data
public class ParameterConfig extends MsParameter {
@ -138,7 +140,7 @@ public class ParameterConfig extends MsParameter {
} else {
apiDefinition = apiDefinitionService.get(samplerProxy.getId());
// 兼容导入数据
if(apiDefinition == null ){
if (apiDefinition == null) {
apiDefinition = apiDefinitionService.get(samplerProxy.getName());
}
ApiTestCaseWithBLOBs apiTestCaseWithBLOBs = apiTestCaseService.get(samplerProxy.getId());
@ -249,4 +251,45 @@ public class ParameterConfig extends MsParameter {
}
return null;
}
public void margeVariables(List<ScenarioVariable> variables, List<ScenarioVariable> transferVariables) {
if (CollectionUtils.isNotEmpty(transferVariables)) {
List<ScenarioVariable> constants = variables.stream().filter(ScenarioVariable::isConstantValid).collect(Collectors.toList());
Map<String, List<ScenarioVariable>> transferVariableGroup =
transferVariables.stream().collect(Collectors.groupingBy(ScenarioVariable::getName, LinkedHashMap::new, Collectors.toList()));
Map<String, List<ScenarioVariable>> constantsGroup =
constants.stream().collect(Collectors.groupingBy(ScenarioVariable::getName, LinkedHashMap::new, Collectors.toList()));
// 更新相同名称的值
for (ScenarioVariable constant : constants) {
if (transferVariableGroup.containsKey(constant.getName())
&& CollectionUtils.isNotEmpty(transferVariableGroup.get(constant.getName()))) {
constant.setValue(transferVariableGroup.get(constant.getName()).get(0).getValue());
}
}
// 添加当前没有的值
transferVariables.forEach(item -> {
if (!constantsGroup.containsKey(item.getName())) {
variables.add(item);
}
});
}
}
public void margeParentVariables(List<ScenarioVariable> variables, MsTestElement parent) {
// 取出父级场景且父场景不是顶级场景
MsScenario scenario = getScenario(parent);
if (scenario == null || BooleanUtils.isFalse(scenario.getMixEnable()) || CollectionUtils.isEmpty(scenario.getVariables())) {
return;
}
this.margeVariables(variables, scenario.getVariables());
}
private MsScenario getScenario(MsTestElement parent) {
if (parent != null && parent instanceof MsScenario) {
return parent.getParent() != null ? (MsScenario) parent : null;
} else if (parent != null && parent.getParent() != null) {
getScenario(parent.getParent());
}
return null;
}
}

View File

@ -51,6 +51,7 @@ public class MsHashTreeService {
public static final String NUM = "num";
public static final String ENV_ENABLE = "environmentEnable";
public static final String VARIABLE_ENABLE = "variableEnable";
public static final String MIX_ENABLE = "mixEnable";
public static final String DISABLED = "disabled";
public static final String VERSION_NAME = "versionName";
public static final String VERSION_ENABLE = "versionEnable";
@ -245,8 +246,8 @@ public class MsHashTreeService {
private JSONObject setRefScenario(JSONObject element) {
boolean enable = element.containsKey(ENABLE) ? element.getBoolean(ENABLE) : true;
if (!element.containsKey(VARIABLE_ENABLE)) {
element.put(VARIABLE_ENABLE, true);
if (!element.containsKey(MIX_ENABLE)) {
element.put(MIX_ENABLE, true);
}
ApiScenarioDTO scenarioWithBLOBs = extApiScenarioMapper.selectById(element.getString(ID));
@ -254,7 +255,9 @@ public class MsHashTreeService {
boolean environmentEnable = element.containsKey(ENV_ENABLE)
? element.getBoolean(ENV_ENABLE) : false;
boolean variableEnable = element.containsKey(VARIABLE_ENABLE)
? element.getBoolean(VARIABLE_ENABLE) : true;
? element.getBoolean(VARIABLE_ENABLE) : false;
boolean mixEnable = element.containsKey(MIX_ENABLE)
? element.getBoolean(MIX_ENABLE) : true;
if (environmentEnable && StringUtils.isNotEmpty(scenarioWithBLOBs.getEnvironmentJson())) {
element.put(ENV_MAP, JSON.parseObject(scenarioWithBLOBs.getEnvironmentJson(), Map.class));
@ -269,6 +272,9 @@ public class MsHashTreeService {
if (!element.containsKey(VARIABLE_ENABLE)) {
element.put(VARIABLE_ENABLE, variableEnable);
}
if (!element.containsKey(MIX_ENABLE) && !variableEnable) {
element.put(MIX_ENABLE, mixEnable);
}
this.setElement(element, scenarioWithBLOBs.getNum(), enable, scenarioWithBLOBs.getVersionName(), scenarioWithBLOBs.getVersionEnable());
} else {
if (StringUtils.equalsIgnoreCase(element.getString(REFERENCED), REF)) {

View File

@ -1271,7 +1271,7 @@ export default {
}
this.resetResourceId(item.hashTree);
item.enable === undefined ? item.enable = true : item.enable;
item.variableEnable = item.variableEnable === undefined ? true : item.variableEnable;
item.mixEnable = item.mixEnable === undefined && !item.variableEnable ? true : item.mixEnable;
if (this.selectedTreeNode !== undefined) {
if (this.stepFilter.get("SpecialSteps").indexOf(this.selectedTreeNode.type) !== -1) {
this.scenarioDefinition.splice(this.selectedTreeNode.index, 0, item);

View File

@ -6,17 +6,27 @@
</el-link>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="copy" v-if="data.command">{{ this.$t('commons.copy') }}</el-dropdown-item>
<el-dropdown-item command="enable" v-if="data.command && data.enable">{{ this.$t('ui.disable') }}</el-dropdown-item>
<el-dropdown-item command="enable" v-if="data.command && !data.enable">{{ this.$t('ui.enable') }}</el-dropdown-item>
<el-dropdown-item command="enable" v-if="data.command && data.enable">{{
this.$t('ui.disable')
}}
</el-dropdown-item>
<el-dropdown-item command="enable" v-if="data.command && !data.enable">{{
this.$t('ui.enable')
}}
</el-dropdown-item>
<el-dropdown-item command="remove">{{ this.$t('api_test.automation.delete_step') }}</el-dropdown-item>
<el-dropdown-item command="rename" v-if="!isScenario">{{ this.$t('test_track.module.rename') }}</el-dropdown-item>
<el-dropdown-item command="rename" v-if="!isScenario">{{
this.$t('test_track.module.rename')
}}
</el-dropdown-item>
<el-dropdown-item command="scenarioVar" v-if="data.type==='scenario'">
{{ this.$t("api_test.automation.view_scene_variables") }}
</el-dropdown-item>
<el-dropdown-item command="openScenario" v-if="data.type==='scenario' && data.referenced==='REF'">
{{ this.$t("api_test.automation.open_scene") }}
</el-dropdown-item>
<el-dropdown-item command="saveAs" v-if="allSamplers.indexOf(data.type)!=-1 && (data.referenced===undefined || data.referenced ==='Created' )">
<el-dropdown-item command="saveAs"
v-if="allSamplers.indexOf(data.type)!=-1 && (data.referenced===undefined || data.referenced ==='Created' )">
{{ this.$t("api_test.automation.save_as_api") }}
</el-dropdown-item>
<el-dropdown-item command="setScenario" v-if="data.type==='scenario'">
@ -30,16 +40,21 @@
<el-dialog
:title="$t('commons.reference_settings')"
:visible.sync="dialogVisible" width="400px">
:visible.sync="dialogVisible" width="700px">
<ul>
<el-tooltip :content="$t('commons.enable_scene_info')" placement="top" v-if = 'showEnableScence'>
<el-tooltip :content="$t('commons.enable_scene_info')" placement="top" v-if='showEnableScence'>
<el-checkbox v-model="data.environmentEnable" @change="checkEnv" :disabled="data.disabled">
{{ $t('commons.enable_scene') }}
</el-checkbox>
</el-tooltip>
<el-checkbox v-model="data.variableEnable" :disabled="data.disabled">
<br/>
<el-checkbox v-model="data.variableEnable" :disabled="data.disabled" @change="variableChange">
{{ $t('commons.variable_scene') }}
</el-checkbox>
<br/>
<el-checkbox v-model="data.mixEnable" :disabled="data.disabled" @change="mixChange">
{{ $t('commons.mix_enable') }}
</el-checkbox>
</ul>
</el-dialog>
@ -85,6 +100,16 @@ export default {
this.allSamplers = this.filter.get('DEFINITION');
},
methods: {
variableChange() {
if (this.data.variableEnable) {
this.data.mixEnable = false;
}
},
mixChange() {
if (this.data.mixEnable) {
this.data.variableEnable = false;
}
},
handleCommand(cmd) {
switch (cmd) {
case "copy":

View File

@ -242,6 +242,7 @@ export default {
testing: "Testing",
enable_scene: "Original scene environment",
variable_scene: "Original scene variable",
mix_enable: "The current scene variable is used first, and the original scene variable is used if there is no",
reference_settings: "Reference settings",
enable_scene_info: "Enable scene environment: the current step uses the original environment configuration of the scene to run",
edit_info: "Edit details",

View File

@ -244,6 +244,7 @@ export default {
edit_info: "编辑详情",
enable_scene: "原场景环境",
variable_scene: "原场景变量",
mix_enable: "优先使用当前场景变量,没有则使用原场景变量",
reference_settings: "场景设置",
enable_scene_info: "启用场景环境:当前步骤使用场景原始环境配置运行",
environment: "运行环境",

View File

@ -244,6 +244,7 @@ export default {
edit_info: "編輯詳情",
enable_scene: "原場景環境",
variable_scene: "原場景变量",
mix_enable: "優先使用當前場景變量,沒有則使用原場景變量",
reference_settings: "场景设置",
enable_scene_info: "啟用場景環境:當前步驟使用場景原始環境配置運行",
environment: "運行環境",