feat(接口测试): 增加场景级别断言配置

This commit is contained in:
Captain.B 2020-11-11 12:08:22 +08:00
parent d772fac5e3
commit 6b443008cd
5 changed files with 149 additions and 124 deletions

View File

@ -1,5 +1,6 @@
package io.metersphere.api.dto.scenario; package io.metersphere.api.dto.scenario;
import io.metersphere.api.dto.scenario.assertions.Assertions;
import io.metersphere.api.dto.scenario.request.Request; import io.metersphere.api.dto.scenario.request.Request;
import lombok.Data; import lombok.Data;
@ -15,6 +16,7 @@ public class Scenario {
private List<KeyValue> variables; private List<KeyValue> variables;
private List<KeyValue> headers; private List<KeyValue> headers;
private List<Request> requests; private List<Request> requests;
private Assertions assertions;
private DubboConfig dubboConfig; private DubboConfig dubboConfig;
private TCPConfig tcpConfig; private TCPConfig tcpConfig;
private List<DatabaseConfig> databaseConfigs; private List<DatabaseConfig> databaseConfigs;

View File

@ -305,6 +305,7 @@
}, },
cancel() { cancel() {
this.$router.push('/api/test/list/all'); this.$router.push('/api/test/list/all');
// console.log(this.test.toJMX().xml);
}, },
handleCommand(command) { handleCommand(command) {
switch (command) { switch (command) {

View File

@ -52,6 +52,9 @@
<el-tab-pane :label="$t('api_test.environment.tcp_config')" name="tcp"> <el-tab-pane :label="$t('api_test.environment.tcp_config')" name="tcp">
<ms-tcp-config :config="scenario.tcpConfig" :is-read-only="isReadOnly"/> <ms-tcp-config :config="scenario.tcpConfig" :is-read-only="isReadOnly"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('api_test.request.assertions.label')" name="assertions">
<ms-api-assertions :scenario="scenario" :is-read-only="isReadOnly" :assertions="scenario.assertions"/>
</el-tab-pane>
</el-tabs> </el-tabs>
<api-environment-config ref="environmentConfig" @close="environmentConfigClose"/> <api-environment-config ref="environmentConfig" @close="environmentConfigClose"/>
@ -72,6 +75,7 @@ import MsDubboConsumerService from "@/business/components/api/test/components/re
import MsDatabaseConfig from "./request/database/DatabaseConfig"; import MsDatabaseConfig from "./request/database/DatabaseConfig";
import {parseEnvironment} from "../model/EnvironmentModel"; import {parseEnvironment} from "../model/EnvironmentModel";
import MsTcpConfig from "@/business/components/api/test/components/request/tcp/TcpConfig"; import MsTcpConfig from "@/business/components/api/test/components/request/tcp/TcpConfig";
import MsApiAssertions from "@/business/components/api/test/components/assertion/ApiAssertions";
export default { export default {
name: "MsApiScenarioForm", name: "MsApiScenarioForm",
@ -79,7 +83,8 @@ export default {
MsTcpConfig, MsTcpConfig,
MsDatabaseConfig, MsDatabaseConfig,
MsDubboConsumerService, MsDubboConsumerService,
MsDubboConfigCenter, MsDubboRegistryCenter, ApiEnvironmentConfig, MsApiScenarioVariables, MsApiKeyValue MsDubboConfigCenter, MsDubboRegistryCenter, ApiEnvironmentConfig, MsApiScenarioVariables, MsApiKeyValue,
MsApiAssertions
}, },
props: { props: {
scenario: Scenario, scenario: Scenario,

View File

@ -3,7 +3,8 @@
<div class="assertion-add"> <div class="assertion-add">
<el-row :gutter="10"> <el-row :gutter="10">
<el-col :span="4"> <el-col :span="4">
<el-select :disabled="isReadOnly" class="assertion-item" v-model="type" :placeholder="$t('api_test.request.assertions.select_type')" <el-select :disabled="isReadOnly" class="assertion-item" v-model="type"
:placeholder="$t('api_test.request.assertions.select_type')"
size="small"> size="small">
<el-option :label="$t('api_test.request.assertions.text')" :value="options.TEXT"/> <el-option :label="$t('api_test.request.assertions.text')" :value="options.TEXT"/>
<el-option :label="$t('api_test.request.assertions.regex')" :value="options.REGEX"/> <el-option :label="$t('api_test.request.assertions.regex')" :value="options.REGEX"/>
@ -14,13 +15,18 @@
</el-select> </el-select>
</el-col> </el-col>
<el-col :span="20"> <el-col :span="20">
<ms-api-assertion-text :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.TEXT" :callback="after"/> <ms-api-assertion-text :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.TEXT"
<ms-api-assertion-regex :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.REGEX" :callback="after"/> :callback="after"/>
<ms-api-assertion-json-path :is-read-only="isReadOnly" :list="assertions.jsonPath" v-if="type === options.JSON_PATH" :callback="after"/> <ms-api-assertion-regex :is-read-only="isReadOnly" :list="assertions.regex" v-if="type === options.REGEX"
<ms-api-assertion-x-path2 :is-read-only="isReadOnly" :list="assertions.xpath2" v-if="type === options.XPATH2" :callback="after"/> :callback="after"/>
<ms-api-assertion-json-path :is-read-only="isReadOnly" :list="assertions.jsonPath"
v-if="type === options.JSON_PATH" :callback="after"/>
<ms-api-assertion-x-path2 :is-read-only="isReadOnly" :list="assertions.xpath2" v-if="type === options.XPATH2"
:callback="after"/>
<ms-api-assertion-duration :is-read-only="isReadOnly" v-model="time" :duration="assertions.duration" <ms-api-assertion-duration :is-read-only="isReadOnly" v-model="time" :duration="assertions.duration"
v-if="type === options.DURATION" :callback="after"/> v-if="type === options.DURATION" :callback="after"/>
<ms-api-assertion-jsr223 :is-read-only="isReadOnly" :list="assertions.jsr223" v-if="type === options.JSR223" :callback="after"/> <ms-api-assertion-jsr223 :is-read-only="isReadOnly" :list="assertions.jsr223" v-if="type === options.JSR223"
:callback="after"/>
<el-button v-if="!type" :disabled="true" type="primary" size="small"> <el-button v-if="!type" :disabled="true" type="primary" size="small">
{{ $t('api_test.request.assertions.add') }} {{ $t('api_test.request.assertions.add') }}
</el-button> </el-button>
@ -28,7 +34,7 @@
</el-row> </el-row>
</div> </div>
<div> <div v-if="!scenario">
<el-row :gutter="10" class="json-path-suggest-button"> <el-row :gutter="10" class="json-path-suggest-button">
<el-button size="small" type="primary" @click="suggestJsonOpen"> <el-button size="small" type="primary" @click="suggestJsonOpen">
{{ $t('api_test.request.assertions.json_path_suggest') }} {{ $t('api_test.request.assertions.json_path_suggest') }}
@ -39,7 +45,8 @@
</el-row> </el-row>
</div> </div>
<ms-api-jsonpath-suggest-list @addJsonpathSuggest="addJsonpathSuggest" :request="request" ref="jsonpathSuggestList"/> <ms-api-jsonpath-suggest-list @addJsonpathSuggest="addJsonpathSuggest" :request="request"
ref="jsonpathSuggestList"/>
<ms-api-assertions-edit :is-read-only="isReadOnly" :assertions="assertions"/> <ms-api-assertions-edit :is-read-only="isReadOnly" :assertions="assertions"/>
</div> </div>
@ -49,7 +56,7 @@
import MsApiAssertionText from "./ApiAssertionText"; import MsApiAssertionText from "./ApiAssertionText";
import MsApiAssertionRegex from "./ApiAssertionRegex"; import MsApiAssertionRegex from "./ApiAssertionRegex";
import MsApiAssertionDuration from "./ApiAssertionDuration"; import MsApiAssertionDuration from "./ApiAssertionDuration";
import {ASSERTION_TYPE, Assertions, HttpRequest, JSONPath} from "../../model/ScenarioModel"; import {ASSERTION_TYPE, Assertions, HttpRequest, JSONPath, Scenario} from "../../model/ScenarioModel";
import MsApiAssertionsEdit from "./ApiAssertionsEdit"; import MsApiAssertionsEdit from "./ApiAssertionsEdit";
import MsApiAssertionJsonPath from "./ApiAssertionJsonPath"; import MsApiAssertionJsonPath from "./ApiAssertionJsonPath";
import MsApiAssertionJsr223 from "@/business/components/api/test/components/assertion/ApiAssertionJsr223"; import MsApiAssertionJsr223 from "@/business/components/api/test/components/assertion/ApiAssertionJsr223";
@ -64,11 +71,13 @@
MsApiAssertionJsr223, MsApiAssertionJsr223,
MsApiJsonpathSuggestList, MsApiJsonpathSuggestList,
MsApiAssertionJsonPath, MsApiAssertionJsonPath,
MsApiAssertionsEdit, MsApiAssertionDuration, MsApiAssertionRegex, MsApiAssertionText}, MsApiAssertionsEdit, MsApiAssertionDuration, MsApiAssertionRegex, MsApiAssertionText
},
props: { props: {
assertions: Assertions, assertions: Assertions,
request: HttpRequest, request: HttpRequest,
scenario: Scenario,
isReadOnly: { isReadOnly: {
type: Boolean, type: Boolean,
default: false default: false

View File

@ -1,5 +1,6 @@
import { import {
Arguments, Arguments,
ConstantTimer as JMXConstantTimer,
CookieManager, CookieManager,
DNSCacheManager, DNSCacheManager,
DubboSample, DubboSample,
@ -10,22 +11,24 @@ import {
HTTPSamplerArguments, HTTPSamplerArguments,
HTTPsamplerFiles, HTTPsamplerFiles,
HTTPSamplerProxy, HTTPSamplerProxy,
IfController as JMXIfController,
JDBCDataSource, JDBCDataSource,
JDBCSampler, JDBCSampler,
JSONPathAssertion, JSONPathAssertion,
JSONPostProcessor, JSONPostProcessor,
JSR223Assertion,
JSR223PostProcessor, JSR223PostProcessor,
JSR223PreProcessor, JSR223PreProcessor,
RegexExtractor, RegexExtractor,
ResponseCodeAssertion, ResponseCodeAssertion,
ResponseDataAssertion, ResponseDataAssertion,
ResponseHeadersAssertion, ResponseHeadersAssertion,
TCPSampler,
TestElement, TestElement,
TestPlan, TestPlan,
ThreadGroup, ThreadGroup,
XPath2Assertion,
XPath2Extractor, XPath2Extractor,
IfController as JMXIfController,
ConstantTimer as JMXConstantTimer, TCPSampler, JSR223Assertion, XPath2Assertion,
} from "./JMX"; } from "./JMX";
import Mock from "mockjs"; import Mock from "mockjs";
import {funcFilters} from "@/common/js/func-filter"; import {funcFilters} from "@/common/js/func-filter";
@ -226,6 +229,7 @@ export class Scenario extends BaseConfig {
this.enable = true; this.enable = true;
this.databaseConfigs = []; this.databaseConfigs = [];
this.tcpConfig = undefined; this.tcpConfig = undefined;
this.assertions = undefined;
this.set(options); this.set(options);
this.sets({ this.sets({
@ -242,6 +246,7 @@ export class Scenario extends BaseConfig {
options.databaseConfigs = options.databaseConfigs || []; options.databaseConfigs = options.databaseConfigs || [];
options.dubboConfig = new DubboConfig(options.dubboConfig); options.dubboConfig = new DubboConfig(options.dubboConfig);
options.tcpConfig = new TCPConfig(options.tcpConfig); options.tcpConfig = new TCPConfig(options.tcpConfig);
options.assertions = new Assertions(options.assertions);
return options; return options;
} }
@ -1151,6 +1156,9 @@ class JMXGenerator {
this.addScenarioCookieManager(threadGroup, scenario); this.addScenarioCookieManager(threadGroup, scenario);
this.addJDBCDataSources(threadGroup, scenario); this.addJDBCDataSources(threadGroup, scenario);
this.addAssertion(threadGroup, scenario);
scenario.requests.forEach(request => { scenario.requests.forEach(request => {
if (request.enable) { if (request.enable) {
if (!request.isValid()) return; if (!request.isValid()) return;
@ -1175,7 +1183,7 @@ class JMXGenerator {
this.addRequestExtractor(sampler, request); this.addRequestExtractor(sampler, request);
this.addRequestAssertion(sampler, request); this.addAssertion(sampler, request);
this.addJSR223PreProcessor(sampler, request); this.addJSR223PreProcessor(sampler, request);
@ -1467,7 +1475,7 @@ class JMXGenerator {
httpSamplerProxy.add(new HTTPsamplerFiles(files)); httpSamplerProxy.add(new HTTPsamplerFiles(files));
} }
addRequestAssertion(httpSamplerProxy, request) { addAssertion(httpSamplerProxy, request) {
let assertions = request.assertions; let assertions = request.assertions;
if (assertions.regex.length > 0) { if (assertions.regex.length > 0) {
assertions.regex.filter(this.filter).forEach(regex => { assertions.regex.filter(this.filter).forEach(regex => {