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

--story=1010745 --user=赵勇 场景嵌套引用的变量取值优化-接口场景 https://www.tapd.cn/55049933/s/1312907
This commit is contained in:
fit2-zhao 2022-12-05 17:19:55 +08:00 committed by 刘瑞斌
parent 00cb5c7343
commit b5ca7416e9
11 changed files with 93 additions and 14 deletions

View File

@ -23,6 +23,7 @@ import io.metersphere.service.MsHashTreeService;
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.jorphan.collections.HashTree;
@ -49,6 +50,7 @@ public class MsScenario extends MsTestElement {
private boolean environmentEnable;
private Boolean variableEnable;
private static final String BODY_FILE_DIR = FileUtils.BODY_FILE_DIR;
private Boolean mixEnable;
public MsScenario() {
}
@ -112,12 +114,20 @@ 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 = ElementUtil.getConfigArguments(this.isEnvironmentEnable() ? newConfig : config, this.getName(), this.getProjectId(), this.getVariables());
if (arguments != null && (this.variableEnable == null || this.variableEnable)) {
Arguments arguments = ElementUtil.getConfigArguments(this.isEnvironmentEnable() ?
newConfig : config, this.getName(), this.getProjectId(), this.getVariables());
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);

View File

@ -22,10 +22,12 @@ import io.metersphere.service.definition.ApiTestCaseService;
import io.metersphere.service.plan.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 {
@ -222,4 +224,45 @@ public class ParameterConfig extends MsParameter {
}
}
}
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

@ -62,6 +62,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";
@ -199,14 +200,17 @@ public class MsHashTreeService {
private JSONObject setRefScenario(JSONObject element) {
boolean enable = element.has(ENABLE) ? element.optBoolean(ENABLE) : true;
if (!element.has(VARIABLE_ENABLE)) {
element.put(VARIABLE_ENABLE, true);
if (!element.has(MIX_ENABLE)) {
element.put(MIX_ENABLE, true);
}
ApiScenarioDTO scenarioWithBLOBs = extApiScenarioMapper.selectById(element.optString(ID));
if (scenarioWithBLOBs != null && StringUtils.isNotEmpty(scenarioWithBLOBs.getScenarioDefinition())) {
boolean environmentEnable = element.has(ENV_ENABLE) ? element.optBoolean(ENV_ENABLE) : false;
boolean variableEnable = element.has(VARIABLE_ENABLE) ? element.optBoolean(VARIABLE_ENABLE) : true;
boolean variableEnable = element.has(VARIABLE_ENABLE) ? element.optBoolean(VARIABLE_ENABLE) : false;
boolean mixEnable = element.has(MIX_ENABLE)
? element.getBoolean(MIX_ENABLE) : true;
if (environmentEnable && StringUtils.isNotEmpty(scenarioWithBLOBs.getEnvironmentJson())) {
element.put(ENV_MAP, JSON.parseObject(scenarioWithBLOBs.getEnvironmentJson(), Map.class));
}
@ -220,6 +224,9 @@ public class MsHashTreeService {
if (!element.has(VARIABLE_ENABLE)) {
element.put(VARIABLE_ENABLE, variableEnable);
}
if (!element.has(MIX_ENABLE) && !variableEnable) {
element.put(MIX_ENABLE, mixEnable);
}
//获取场景的当前项目是否开启了自定义id
ProjectConfig projectApplication = baseProjectApplicationService.getSpecificTypeValue(scenarioWithBLOBs.getProjectId(), "SCENARIO_CUSTOM_NUM");
element.put(SHOW_CUSTOM_NUM, projectApplication.getScenarioCustomNum());

View File

@ -1524,7 +1524,7 @@ export default {
}
this.resetResourceId(item.hashTree, item.referenced);
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) {
if (this.stepFilter.get('SpecialSteps').indexOf(this.selectedTreeNode.type) !== -1) {
this.scenarioDefinition.splice(this.selectedTreeNode.index, 0, item);

View File

@ -42,16 +42,22 @@
<ms-add-api-case :currentProtocol="currentProtocol" ref="apiCase" />
<el-dialog :title="$t('commons.reference_settings')" :visible.sync="dialogVisible" width="400px">
<el-dialog :title="$t('commons.reference_settings')" :visible.sync="dialogVisible" width="700px">
<ul>
<el-tooltip :content="$t('commons.enable_scene_info')" placement="top" v-if="showEnableScenario">
<el-checkbox v-model="data.environmentEnable" @change="checkEnv">
{{ $t('commons.enable_scene') }}
</el-checkbox>
</el-tooltip>
<el-checkbox v-model="data.variableEnable">
<br />
<el-checkbox v-model="data.variableEnable" @change="variableChange">
{{ $t('commons.variable_scene') }}
</el-checkbox>
<br />
<el-checkbox v-model="data.mixEnable" @change="mixChange">
{{ $t('api_case.mix_enable') }}
</el-checkbox>
</ul>
</el-dialog>
</div>
@ -100,6 +106,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

@ -5,6 +5,7 @@ import mf from 'metersphere-frontend/src/i18n/lang/en-US';
const message = {
api_case: {
please_add_api_case: 'Please add api case',
mix_enable: 'The current scene variable is used first, and the original scene variable is used if there is no',
},
api_definition: {
debug_pool_warning:

View File

@ -5,6 +5,7 @@ import mf from 'metersphere-frontend/src/i18n/lang/zh-CN';
const message = {
api_case: {
please_add_api_case: '请先添加接口用例',
mix_enable: '优先使用当前场景变量,没有则使用原场景变量',
},
api_definition: {
debug_pool_warning: '调用资源池执行失败,请检查资源池是否配置正常',

View File

@ -5,6 +5,7 @@ import mf from 'metersphere-frontend/src/i18n/lang/zh-TW';
const message = {
api_case: {
please_add_api_case: '请先添加接口用例',
mix_enable: '優先使用當前場景變量,沒有則使用原場景變量',
},
api_definition: {
debug_pool_warning: '調用資源池執行失敗,請檢查資源池是否配置正常',

View File

@ -60,7 +60,7 @@ export default {
return this.height ? (this.height + 'px') : (this.enableAutoHeight ? null : 'calc(100vh - 50px)')
},
containerCalHeight() {
return this.height ? (this.height - 30 + 'px') : (this.enableAutoHeight ? null : 'calc(100vh - 60px)')
return this.height ? (this.height - 30 + 'px') : (this.enableAutoHeight ? null : 'calc(100vh - 62px)')
},
},
created() {

View File

@ -34,8 +34,8 @@ a:hover {
/* 滚动条样式 */
::-webkit-scrollbar{
width: 10px;
height: 10px;
width: 8px;
height: 8px;
position: fixed;
}
::-webkit-scrollbar-thumb{

View File

@ -197,8 +197,8 @@ textarea {
/* 滚动条样式 */
::-webkit-scrollbar{
width: 10px;
height: 10px;
width: 8px;
height: 8px;
position: fixed;
}
::-webkit-scrollbar-thumb{