refactor(接口测试): 优化JSONPath断言匹配机制,支持正则忽略数字精度匹配
--story=1012676 --user=赵勇 jsonpath 断言精度匹配优化 https://www.tapd.cn/55049933/s/1399645 Signed-off-by: fit2-zhao <yong.zhao@fit2cloud.com>
This commit is contained in:
parent
d0075a710d
commit
4822880d91
|
@ -43,7 +43,6 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is main class for JSONPath Assertion which verifies assertion on
|
* This is main class for JSONPath Assertion which verifies assertion on
|
||||||
|
@ -64,7 +63,7 @@ public class JSONPathAssertion extends AbstractTestElement implements Serializab
|
||||||
private static final boolean USE_JAVA_REGEX = !JMeterUtils.getPropDefault(
|
private static final boolean USE_JAVA_REGEX = !JMeterUtils.getPropDefault(
|
||||||
"jmeter.regex.engine", "oro").equalsIgnoreCase("oro");
|
"jmeter.regex.engine", "oro").equalsIgnoreCase("oro");
|
||||||
|
|
||||||
private static ThreadLocal<DecimalFormat> decimalFormatter =
|
private static final ThreadLocal<DecimalFormat> decimalFormatter =
|
||||||
ThreadLocal.withInitial(JSONPathAssertion::createDecimalFormat);
|
ThreadLocal.withInitial(JSONPathAssertion::createDecimalFormat);
|
||||||
|
|
||||||
private static DecimalFormat createDecimalFormat() {
|
private static DecimalFormat createDecimalFormat() {
|
||||||
|
@ -133,8 +132,7 @@ public class JSONPathAssertion extends AbstractTestElement implements Serializab
|
||||||
private void doAssert(String jsonString) {
|
private void doAssert(String jsonString) {
|
||||||
Object value = JsonPath.read(jsonString, getJsonPath());
|
Object value = JsonPath.read(jsonString, getJsonPath());
|
||||||
if (!isJsonValidationBool()) {
|
if (!isJsonValidationBool()) {
|
||||||
if (value instanceof JSONArray) {
|
if (value instanceof JSONArray arrayValue) {
|
||||||
JSONArray arrayValue = (JSONArray) value;
|
|
||||||
if (arrayValue.isEmpty() && !JsonPath.isPathDefinite(getJsonPath())) {
|
if (arrayValue.isEmpty() && !JsonPath.isPathDefinite(getJsonPath())) {
|
||||||
throw new IllegalStateException("JSONPath is indefinite and the extracted Value is an empty Array." +
|
throw new IllegalStateException("JSONPath is indefinite and the extracted Value is an empty Array." +
|
||||||
" Please use an assertion value, to be sure to get a correct result. " + getExpectedValue());
|
" Please use an assertion value, to be sure to get a correct result. " + getExpectedValue());
|
||||||
|
@ -148,8 +146,7 @@ public class JSONPathAssertion extends AbstractTestElement implements Serializab
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((isExpectNull() && value == null)
|
if ((isExpectNull() && value == null) || assertMatch(value)) {
|
||||||
|| isEquals(value)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,30 +157,18 @@ public class JSONPathAssertion extends AbstractTestElement implements Serializab
|
||||||
String msg = "";
|
String msg = "";
|
||||||
if (this.isUseRegex()) {
|
if (this.isUseRegex()) {
|
||||||
msg = "Value expected to match regexp '%s', but it did not match: '%s'";
|
msg = "Value expected to match regexp '%s', but it did not match: '%s'";
|
||||||
} else if (StringUtils.isNotEmpty(getOption()) && !this.isEquals(value)) {
|
} else if (StringUtils.isNotEmpty(getOption()) && !this.assertMatch(value)) {
|
||||||
switch (getOption()) {
|
msg = switch (getOption()) {
|
||||||
case "CONTAINS":
|
case "CONTAINS" -> "Value contains to be '%s', but found '%s'";
|
||||||
msg = "Value contains to be '%s', but found '%s'";
|
case "NOT_CONTAINS" -> "Value not contains to be '%s', but found '%s'";
|
||||||
break;
|
case "EQUALS" -> "Value equals to be '%s', but found '%s'";
|
||||||
case "NOT_CONTAINS":
|
case "NOT_EQUALS" -> "Value not equals to be '%s', but found '%s'";
|
||||||
msg = "Value not contains to be '%s', but found '%s'";
|
case "GT" -> "Value > '%s', but found '%s'";
|
||||||
break;
|
case "LT" -> "Value < '%s', but found '%s'";
|
||||||
case "EQUALS":
|
case "DOCUMENT" ->
|
||||||
msg = "Value equals to be '%s', but found '%s'";
|
DocumentUtils.documentMsg(this.getName(), value, this.getElementCondition(), decimalFormatter);
|
||||||
break;
|
default -> msg;
|
||||||
case "NOT_EQUALS":
|
};
|
||||||
msg = "Value not equals to be '%s', but found '%s'";
|
|
||||||
break;
|
|
||||||
case "GT":
|
|
||||||
msg = "Value > '%s', but found '%s'";
|
|
||||||
break;
|
|
||||||
case "LT":
|
|
||||||
msg = "Value < '%s', but found '%s'";
|
|
||||||
break;
|
|
||||||
case "DOCUMENT":
|
|
||||||
msg = DocumentUtils.documentMsg(this.getName(), value, this.getElementCondition(),decimalFormatter);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
msg = "Value expected to be '%s', but found '%s'";
|
msg = "Value expected to be '%s', but found '%s'";
|
||||||
}
|
}
|
||||||
|
@ -208,27 +193,27 @@ public class JSONPathAssertion extends AbstractTestElement implements Serializab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isDocument) {
|
if (isDocument) {
|
||||||
return isEquals(value);
|
return assertMatch(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Object subj : value.toArray()) {
|
for (Object subj : value.toArray()) {
|
||||||
if (!StringUtils.equals(getOption(), "NOT_CONTAINS")) {
|
if (!StringUtils.equals(getOption(), "NOT_CONTAINS")) {
|
||||||
if (subj == null && this.isExpectNull() || isEquals(subj)) {
|
if (subj == null && this.isExpectNull() || assertMatch(subj)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.add(isEquals(subj));
|
result.add(assertMatch(subj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(result) && StringUtils.equals(getOption(), "NOT_CONTAINS")) {
|
if (CollectionUtils.isNotEmpty(result) && StringUtils.equals(getOption(), "NOT_CONTAINS")) {
|
||||||
if (result.stream().filter(item -> item == true).collect(Collectors.toList()).size() == result.size()) {
|
if (result.stream().filter(item -> item).toList().size() == result.size()) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return isEquals(value);
|
return assertMatch(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isGt(String v1, String v2) {
|
private boolean isGt(String v1, String v2) {
|
||||||
|
@ -251,42 +236,41 @@ public class JSONPathAssertion extends AbstractTestElement implements Serializab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isEquals(Object subj) {
|
private boolean assertMatch(Object subj) {
|
||||||
String str = DocumentUtils.objectToString(subj, decimalFormatter);
|
|
||||||
if (isUseRegex()) {
|
if (isUseRegex()) {
|
||||||
if (USE_JAVA_REGEX) {
|
String expectedValue = getExpectedValue();
|
||||||
return JMeterUtils.compilePattern(getExpectedValue()).matcher(str).matches();
|
String resultValue;
|
||||||
|
if (subj instanceof BigDecimal) {
|
||||||
|
resultValue = String.valueOf(((BigDecimal) subj).doubleValue());
|
||||||
|
try {
|
||||||
|
Double.parseDouble(getExpectedValue());
|
||||||
|
expectedValue = String.valueOf(Double.parseDouble(getExpectedValue()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
expectedValue = getExpectedValue();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Pattern pattern = JMeterUtils.getPatternCache().getPattern(getExpectedValue());
|
resultValue = DocumentUtils.objectToString(subj, decimalFormatter);
|
||||||
return JMeterUtils.getMatcher().matches(str, pattern);
|
}
|
||||||
|
if (USE_JAVA_REGEX) {
|
||||||
|
return JMeterUtils.compilePattern(expectedValue).matcher(resultValue).matches();
|
||||||
|
} else {
|
||||||
|
Pattern pattern = JMeterUtils.getPatternCache().getPattern(expectedValue);
|
||||||
|
return JMeterUtils.getMatcher().matches(resultValue, pattern);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
String str = DocumentUtils.objectToString(subj, decimalFormatter);
|
||||||
if (StringUtils.isNotEmpty(getOption())) {
|
if (StringUtils.isNotEmpty(getOption())) {
|
||||||
boolean refFlag = false;
|
return switch (getOption()) {
|
||||||
switch (getOption()) {
|
case "CONTAINS" -> str.contains(getExpectedValue());
|
||||||
case "CONTAINS":
|
case "NOT_CONTAINS" -> !str.contains(getExpectedValue());
|
||||||
refFlag = str.contains(getExpectedValue());
|
case "EQUALS" -> valueEquals(str, getExpectedValue());
|
||||||
break;
|
case "NOT_EQUALS" -> valueNotEquals(str, getExpectedValue());
|
||||||
case "NOT_CONTAINS":
|
case "GT" -> isGt(str, getExpectedValue());
|
||||||
refFlag = !str.contains(getExpectedValue());
|
case "LT" -> isLt(str, getExpectedValue());
|
||||||
break;
|
case "DOCUMENT" ->
|
||||||
case "EQUALS":
|
DocumentUtils.documentChecked(subj, this.getElementCondition(), decimalFormatter);
|
||||||
refFlag = valueEquals(str, getExpectedValue());
|
default -> false;
|
||||||
break;
|
};
|
||||||
case "NOT_EQUALS":
|
|
||||||
refFlag = valueNotEquals(str, getExpectedValue());
|
|
||||||
break;
|
|
||||||
case "GT":
|
|
||||||
refFlag = isGt(str, getExpectedValue());
|
|
||||||
break;
|
|
||||||
case "LT":
|
|
||||||
refFlag = isLt(str, getExpectedValue());
|
|
||||||
break;
|
|
||||||
case "DOCUMENT":
|
|
||||||
refFlag = DocumentUtils.documentChecked(subj, this.getElementCondition(), decimalFormatter);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return refFlag;
|
|
||||||
}
|
}
|
||||||
Object expected = JSONValue.parse(getExpectedValue());
|
Object expected = JSONValue.parse(getExpectedValue());
|
||||||
return Objects.equals(expected, subj);
|
return Objects.equals(expected, subj);
|
||||||
|
@ -359,7 +343,7 @@ public class JSONPathAssertion extends AbstractTestElement implements Serializab
|
||||||
} else if (subj instanceof Map) {
|
} else if (subj instanceof Map) {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
str = new JSONObject((Map<String, ?>) subj).toJSONString();
|
str = new JSONObject((Map<String, ?>) subj).toJSONString();
|
||||||
} else if (subj instanceof Double || subj instanceof Float) {
|
} else if (subj instanceof Double || subj instanceof Float || subj instanceof BigDecimal) {
|
||||||
str = decimalFormatter.get().format(subj);
|
str = decimalFormatter.get().format(subj);
|
||||||
} else {
|
} else {
|
||||||
str = subj.toString();
|
str = subj.toString();
|
||||||
|
|
Loading…
Reference in New Issue