fix(接口测试): json-schema自动生成没有按长度截取

--bug=1044063 --user=陈建星 【接口测试】接口-json请求参数-schema格式-跟节点array类型-无子字段-高级设置最大最小元素数量-自动生成数据为空数组 https://www.tapd.cn/55049933/s/1549783
This commit is contained in:
AgAngle 2024-07-17 15:35:21 +08:00 committed by 刘瑞斌
parent 9b6184057f
commit cfcf184a0d
3 changed files with 53 additions and 30 deletions

View File

@ -32,8 +32,6 @@ public class JsonSchemaBuilder {
}
private static JsonNode generateJson(JsonNode jsonSchemaNode, Map<String, String> processMap, boolean isPreview) {
ObjectNode jsonNode = ApiDataUtils.createObjectNode();
if (jsonSchemaNode instanceof NullNode) {
return NullNode.getInstance();
}
@ -42,6 +40,7 @@ public class JsonSchemaBuilder {
JsonNode propertiesNode = jsonSchemaNode.get(PropertyConstant.PROPERTIES);
// 遍历 properties
if (propertiesNode != null) {
ObjectNode jsonNode = ApiDataUtils.createObjectNode();
propertiesNode.fields().forEachRemaining(entry -> {
String propertyName = entry.getKey();
JsonNode propertyNode = entry.getValue();
@ -51,20 +50,38 @@ public class JsonSchemaBuilder {
// 将属性和值添加到 JSON 对象节点
jsonNode.set(propertyName, valueNode);
});
return jsonNode;
}
} else if (StringUtils.equals(type, PropertyConstant.ARRAY)) {
JsonNode items = jsonSchemaNode.get(PropertyConstant.ITEMS);
JsonNode maxItems = jsonSchemaNode.get(PropertyConstant.MAX_ITEMS);
JsonNode minItems = jsonSchemaNode.get(PropertyConstant.MIN_ITEMS);
if (items != null) {
ArrayNode arrayNode = new ArrayNode(JsonNodeFactory.instance);
items.forEach(item -> {
JsonNode valueNode = isPreview ? generateValueForPreview(null, item, processMap)
: generateValue(null, item, processMap);
arrayNode.add(valueNode);
});
if (isPreview) {
items.forEach(item -> arrayNode.add(generateValueForPreview(null, item, processMap)));
} else {
int max = isTextNotBlank(maxItems) ? maxItems.asInt() : Integer.MAX_VALUE;
int min = isTextNotBlank(minItems) ? minItems.asInt() : 0;
// 自动生成数据根据 minItems maxItems 生成
int itemSize = Math.min(items.size(), max);
for (int i = 0; i < itemSize; i++) {
JsonNode itemNode = items.get(i);
JsonNode valueNode = generateValue(null, itemNode, processMap);
arrayNode.add(valueNode);
}
if (min > itemSize) {
for (int i = itemSize; i < min; i++) {
// 如果不足最小个数则默认补充字符类型的数组项
TextNode itemNode = new TextNode(generateStr(8));
arrayNode.add(itemNode);
}
}
}
return arrayNode;
}
}
return jsonNode;
return null;
}
private static JsonNode generateValueForPreview(String propertyName, JsonNode propertyNode, Map<String, String> processMap) {
@ -75,8 +92,7 @@ public class JsonSchemaBuilder {
String type = getPropertyTextValue(propertyNode, PropertyConstant.TYPE);
String value = getPropertyTextValue(propertyNode, PropertyConstant.EXAMPLE);
return switch (type) {
case PropertyConstant.STRING ->
new TextNode(StringUtils.isBlank(value) ? "string" : value);
case PropertyConstant.STRING -> new TextNode(StringUtils.isBlank(value) ? "string" : value);
case PropertyConstant.INTEGER -> {
if (isVariable(value)) {
yield getJsonNodes(propertyName, processMap, value);
@ -103,14 +119,7 @@ public class JsonSchemaBuilder {
}
}
case PropertyConstant.OBJECT -> generateJson(propertyNode, processMap, true);
case PropertyConstant.ARRAY -> {
ArrayNode arrayNode = new ArrayNode(JsonNodeFactory.instance);
JsonNode items = propertyNode.get(PropertyConstant.ITEMS);
if (items != null) {
items.forEach(item -> arrayNode.add(generateValueForPreview(null, item, processMap)));
}
yield arrayNode;
}
case PropertyConstant.ARRAY -> generateJson(propertyNode, processMap, true);
default -> NullNode.getInstance();
};
@ -135,13 +144,22 @@ public class JsonSchemaBuilder {
int min = isTextNotBlank(minLength) ? minLength.asInt() : 1;
if (enumValues != null && enumValues instanceof ArrayNode) {
value = enumValues.get(new Random().nextInt(enumValues.size())).asText();
} else if (isTextNotBlank(defaultValue)) {
value = defaultValue.asText();
if (value.length() > max) {
value = value.substring(0, max);
}
} else if (isTextNotBlank(pattern)) {
Xeger generator = new Xeger(pattern.asText());
value = generator.generate();
} else if (isTextNotBlank(defaultValue)) {
value = defaultValue.asText();
if (value.length() > max) {
value = value.substring(0, max);
}
if (value.length() < min) {
value = value + generateStr(min - value.length());
}
} else {
value = RandomStringGenerator.builder().withinRange('0', 'z').build().generate(new Random().nextInt(max - min + 1) + min);
value = generateStr(new Random().nextInt(max - min + 1) + min);
}
}
yield new TextNode(value);
@ -207,20 +225,17 @@ public class JsonSchemaBuilder {
yield BooleanNode.valueOf(propertyNode.get(PropertyConstant.EXAMPLE).asBoolean());
}
}
case PropertyConstant.OBJECT -> generateJson(propertyNode, processMap, true);
case PropertyConstant.ARRAY -> {
ArrayNode arrayNode = new ArrayNode(JsonNodeFactory.instance);
JsonNode items = propertyNode.get(PropertyConstant.ITEMS);
if (items != null) {
items.forEach(item -> arrayNode.add(generateValue(null, item, processMap)));
}
yield arrayNode;
}
case PropertyConstant.OBJECT -> generateJson(propertyNode, processMap, false);
case PropertyConstant.ARRAY -> generateJson(propertyNode, processMap, false);
default -> NullNode.getInstance();
};
}
private static String generateStr(int length) {
return RandomStringGenerator.builder().withinRange('0', 'z').build().generate(length);
}
private static boolean isTextNotBlank(JsonNode jsonNode) {
return jsonNode != null && !(jsonNode instanceof NullNode) && StringUtils.isNotBlank(jsonNode.asText());
}

View File

@ -1801,6 +1801,12 @@ public class ApiDefinitionControllerTests extends BaseTest {
{"id":null,"title":null,"example":null,"type":"object","description":null,"items":null,"properties":{"array":{"id":null,"title":null,"example":null,"type":"array","description":null,"items":[{"id":null,"title":null,"example":"","type":"string","description":"","items":null,"properties":null,"additionalProperties":null,"required":null,"defaultValue":"默认值","pattern":null,"maxLength":4,"minLength":0,"minimum":null,"maximum":null,"maxItems":null,"minItems":null,"format":null,"enumValues":null,"enable":true},{"id":null,"title":null,"example":"","type":"number","description":"","items":null,"properties":null,"additionalProperties":null,"required":null,"defaultValue":"","pattern":null,"maxLength":null,"minLength":null,"minimum":null,"maximum":null,"maxItems":null,"minItems":null,"format":null,"enumValues":null,"enable":true}],"properties":null,"additionalProperties":null,"required":null,"defaultValue":null,"pattern":null,"maxLength":null,"minLength":null,"minimum":null,"maximum":null,"maxItems":null,"minItems":null,"format":null,"enumValues":null,"enable":true},"string":{"id":null,"title":null,"example":"","type":"string","description":"","items":null,"properties":null,"additionalProperties":null,"required":null,"defaultValue":"","pattern":"[A-Z0-9_]+","maxLength":5,"minLength":1,"minimum":null,"maximum":null,"maxItems":null,"minItems":null,"format":null,"enumValues":null,"enable":true},"int":{"id":null,"title":null,"example":"","type":"integer","description":"","items":null,"properties":null,"additionalProperties":null,"required":null,"defaultValue":3,"pattern":null,"maxLength":null,"minLength":null,"minimum":0,"maximum":4,"maxItems":null,"minItems":null,"format":null,"enumValues":null,"enable":true},"num":{"id":null,"title":null,"example":"","type":"number","description":"","items":null,"properties":null,"additionalProperties":null,"required":null,"defaultValue":2,"pattern":null,"maxLength":null,"minLength":null,"minimum":0,"maximum":5,"maxItems":null,"minItems":null,"format":null,"enumValues":null,"enable":true},"boolean":{"id":null,"title":null,"example":"","type":"boolean","description":"","items":null,"properties":null,"additionalProperties":null,"required":null,"defaultValue":"true","pattern":null,"maxLength":null,"minLength":null,"minimum":null,"maximum":null,"maxItems":null,"minItems":null,"format":null,"enumValues":null,"enable":true},"null":{"id":null,"title":null,"example":null,"type":"null","description":null,"items":null,"properties":null,"additionalProperties":null,"required":null,"defaultValue":null,"pattern":null,"maxLength":null,"minLength":null,"minimum":null,"maximum":null,"maxItems":null,"minItems":null,"format":null,"enumValues":null,"enable":true}},"additionalProperties":null,"required":null,"defaultValue":null,"pattern":null,"maxLength":null,"minLength":null,"minimum":null,"maximum":null,"maxItems":null,"minItems":null,"format":null,"enumValues":null,"enable":true}
""";
requestPostWithOk(JSON_SCHEMA_AUTO_GENERATE, JSON.parseObject(jsonString, JsonSchemaItem.class));
// 长度截取
jsonString = """
{"type":"object","enable":true,"properties":{"arraywww":{"type":"array","enable":true,"items":[{"type":"string","example":"1","description":"","additionalProperties":null,"defaultValue":"","pattern":null,"maxLength":null,"minLength":null,"minimum":null,"maximum":null,"maxItems":null,"minItems":null,"format":null,"enable":true},{"type":"number","example":"2","description":"","additionalProperties":null,"defaultValue":"","pattern":null,"maxLength":null,"minLength":null,"minimum":null,"maximum":null,"maxItems":null,"minItems":null,"format":null,"enable":true}],"minItems":null,"maxItems":null},"string":{"type":"string","example":"@natural(1,100)","description":"","additionalProperties":null,"defaultValue":"","pattern":null,"maxLength":null,"minLength":null,"minimum":null,"maximum":null,"maxItems":null,"minItems":null,"format":null,"enable":true},"int":{"type":"integer","example":"intValue","description":"","additionalProperties":null,"defaultValue":"","pattern":null,"maxLength":null,"minLength":null,"minimum":null,"maximum":null,"maxItems":null,"minItems":null,"format":null,"enable":true},"num":{"type":"number","example":"","description":"","additionalProperties":null,"defaultValue":"","pattern":null,"maxLength":null,"minLength":null,"minimum":null,"maximum":null,"maxItems":null,"minItems":null,"format":null,"enable":true},"boolean":{"type":"boolean","example":"booleanValue","description":"","additionalProperties":null,"defaultValue":"","pattern":null,"maxLength":null,"minLength":null,"minimum":null,"maximum":null,"maxItems":null,"minItems":null,"format":null,"enable":true},"null":{"type":"null","enable":true},"默认值大于最大长度":{"type":"string","example":"","description":"","enable":true,"defaultValue":"sdfdsd","maxLength":1,"minLength":0},"默认值小于最小长度":{"type":"string","example":"","description":"","enable":true,"defaultValue":"1","maxLength":3,"minLength":2},"数组项小于最小项":{"type":"array","enable":true,"items":[],"minItems":2,"maxItems":3},"数组项大于最大项":{"type":"array","enable":true,"items":[null,null],"minItems":0,"maxItems":1},"正则大于最大长度":{"type":"string","example":"","description":"","enable":true,"defaultValue":"","maxLength":2,"minLength":0,"pattern":"[A-Z]{4}"}}}
""";
requestPostWithOk(JSON_SCHEMA_AUTO_GENERATE, JSON.parseObject(jsonString, JsonSchemaItem.class));
}
@Test

View File

@ -29,5 +29,7 @@ public class PropertyConstant {
public final static String MIN_LENGTH = "minLength";
public final static String MINIMUM = "minimum";
public final static String MAXIMUM = "maximum";
public final static String MAX_ITEMS = "maxItems";
public final static String MIN_ITEMS = "minItems";
}