- jmeter
- beanshell
- jmeter 验证json结构
- jmeter 验证json中的固定值
1. 什么是Json Schema
定义Json的数据结构与类型
http://json-schema.org/
使用的时候需要注意draft的版本号
2. Json Schema示例
JSON示例
{
"status": false,
"data": [{
"type": "A",
"content": [{
"value": "AAA",
"count": 3
},
{
"value": "BBB",
"count": 4
},
{
"value": "CCC",
"count": 5
},
]
}]
}
对应的JSON schema 示例
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"status": {
"type": "boolean"
},
"data": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"type": {
"type": "string"
},
"content": {
"type": "array",
"items":
{
"type": "object",
"properties": {
"value": {
"type": "string"
},
"count": {
"type": "integer"
}
},
"required": [
"value",
"count"
]
}
}
},
"required": [
"type",
"content"
]
}
]
}
},
"required": [
"status",
"data"
]
}
- $schema 指定JsonSchema指定的版本号
- "type" 指定这个Json节点的数据类型,如 "object" "array" "string" "integer" "boolean"
- "properties":当父类型为“array”时,可以使用"properties"定义其子节点的属性
- "items": 当父类型为“object”时,可以使用"array"定义其子节点的属性
- "required": 当某个属性必须存在时,可以使用required, 当做Json scheme validate时,如果json中不存在这个属性,则会报错
- "enum": 当值不在范围内时,验证时会报fail
"properties": {
"status": {
"type": "boolean",
"enum": [false]
}
3. Json Schema的生成
有些在线工具支持根据Json生成JsonSchema
Draft4
https://www.liquid-technologies.com/online-json-to-schema-converter
特别注意:
可以删除JsonSchem中的重复元素
例如上面的例子中,生成的JsonSchema中含有多个重复的
{
"type": "object",
"properties": {
"value": {
"type": "string"
},
"count": {
"type": "integer"
}
},
"required": [
"value",
"count"
]
}
删除以后,也需要删除"item"后面的 [ ]
删除以后的示例:
"content": {
"type": "array",
"items":
{
"type": "object",
"properties": {
"value": {
"type": "string"
},
"count": {
"type": "integer"
}
},
"required": [
"value",
"count"
]
}
}
Draft 6,7
https://jsonschema.net/#/
4. Java 根据JsonSchema 验证Json
使用的包是json-schema-validator 2.2.6
https://github.com/java-json-tools/json-schema-validator
com.github.fge
json-schema-validator
2.2.6
com.google.guava
guava
18.0
Jmeter 的bean shell 使用java代码必须catch所有异常,不能Throw
verifyJsonSchema 返回"test pass" or "test fail 与错误报告" or "test fail 与Excerption",Jmeter中根据pass fail,输入assert结果
import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jackson.JsonLoader;
import com.github.fge.jsonschema.SchemaVersion;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import com.github.fge.jsonschema.core.report.ProcessingReport;
import com.github.fge.jsonschema.main.JsonSchema;
import com.github.fge.jsonschema.main.JsonSchemaFactory;
import java.io.IOException;
public class JsonSchemaTool
{
public String verifyJsonSchema(String schemaFileName,String jsonStr) {
try{
String PKGBASE = String.valueOf('/') ;
JsonNode fstabSchema = JsonLoader.fromResource(PKGBASE + schemaFileName);
JsonNode good = JsonLoader.fromString(jsonStr);
JsonSchemaFactory factory = JsonSchemaFactory.byDefault();
JsonSchema schema = factory.getJsonSchema(fstabSchema);
ProcessingReport report;
report = schema.validate(good);
System.out.println(report);
StringBuilder sb = new StringBuilder();
if (report.toString().contains("ListProcessingReport: success")){
sb.append("test pass");
}
if (report.toString().contains("ListProcessingReport: failure")){
sb.append("test fail") ;
sb.append("\n") ;
sb.append(report.toString()) ;
}
if(report.toString().contains("level: \"warning\"")){
sb.append("\n") ;
sb.append(" with warning!!!");
}
return sb.toString();
//返回"test pass" or "test fail 与错误报告" or "test fail 与Excerption"
//Jmeter 的bean shell 使用java代码必须catch所有异常,不能Throw
}catch (IOException e){
return "IOException " + e.getMessage();
}catch (ProcessingException e){
return "ProcessingException" + e.getMessage();
}
}
public static void main( String[] args)
{
String suggest_schema_test_json = "{\n" +
"\t\"status\": false,\n" +
"\t\"data\": [{\n" +
"\t\t\"type\": \"A\",\n" +
"\t\t\"content\": [{\n" +
"\t\t\t\"value2\": \"AAA\",\n" +
"\t\t\t\"count\": \"abc\"\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"value\": \"BBB\",\n" +
"\t\t\t\"count\": 4\n" +
"\t\t},\n" +
"\t\t{\n" +
"\t\t\t\"value\": \"CCC\",\n" +
"\t\t\t\"count\": 6\n" +
"\t\t}\n" +
"\t\t]\n" +
"\t}]\n" +
"}";
System.out.println(new JsonSchemaTool().verifyJsonSchema("/suggest_schema.json",suggest_schema_test_json));
}
}
目录结构
运行结果:
例如 缺少一个required的属性,或者 属性的类型错误
输出的验证失败的原因。
test fail
com.github.fge.jsonschema.core.report.ListProcessingReport: failure
--- BEGIN MESSAGES ---
error: object has missing required properties (["value"])
level: "error"
schema: {"loadingURI":"#","pointer":"/properties/data/items/0/properties/content/items"}
instance: {"pointer":"/data/0/content/0"}
domain: "validation"
keyword: "required"
required: ["count","value"]
missing: ["value"]
--- END MESSAGES ---
- Jmeter中使用BeanShell集成 JsonSchemaTool
-
Jmeter中配置JsonSchema所在的路径
-
Jmeter中定义java文件所在的路径
-
BeanShell 结构
BeanShell PreProcessor-getResponse
String response_data = prev.getResponseDataAsString();
vars.put("response_data",response_data);
log.info("-----------response_data------------------"+response_data);
- BeanShell PostProcessor-generateTestResult
String schemapath = vars.get("schemapath");
source(schemapath);
String response_data = vars.get("response_data");
try{
String assertResult = new JsonSchemaTool().verifyJsonSchema("/suggest_schema.json",response_data);
log.info("-----------assertResult------------------"+assertResult);
vars.put("assertResult",assertResult);
} catch (Throwable ex) {
log.error("Beanshell failure: ", ex);
throw ex;
}
- BeanShell Assert
String assertResult = vars.get("assertResult");
log.info("-----beanshell assert------assertResult------------------"+assertResult);
if(assertResult.contains("test fail")){
Failure = true;
FailureMessage = assertResult;
}
-
Jmeter运行Test
需要的jar包放置在本地的Jmeter路径下
D:\TestTools\apache-jmeter-3.1\lib\ext