原文地址: https://www.jianshu.com/p/1711f2f24dcf

JsonSchema官方文档入门文档入门文档生成Schema工具

使用Json的好处(什么是Schema):

  • 描述现有的数据格式
  • 提供清晰的人工和机器可读文档
  • 完整的数据结构,有利于自动化测试
  • 完整的数据结构,有利于验证客户端提交数据的质量

什么是JSON Schema

  • JSON Schema本身就是一种数据结构,可以清晰的描述JSON数据的结构。是一种描述JSON数据的JSON数据。

使用JSON Schema的好处

  • JSON Schema 非常适用于基于JSON的HTTP的API。
  • JSON Schema从Java的基本数据类型中对JSON结构进行校验,所以对JSON结构的校验可以理解为对每种不同数据类型的相应校验。
  • 接口测试中可以快速的定位到自己数据格式的正确性。

JSON模式示例

{ "$schema":"<http://json-schema.org/draft-04/schema#>", "title":"book info", "description":"some information about book", "type":"object", "properties":{ "id":{ "description":"The unique identifier for a book", "type":"integer", "minimum":1 }, "name":{ "type":"string", "pattern":"^#([0-9a-fA-F]{6}$", "maxLength":6, "minLength":6 }, "price":{ "type":"number", "multipleOf":0.5, "maximum":12.5, "exclusiveMaximum":true, "minimum":2.5, "exclusiveMinimum":true }, "tags":{ "type":"array", "items":[ { "type":"string", "minLength":5 }, { "type":"number", "minimum":10 } ], "additionalItems":{ "type":"string", "minLength":2 }, "minItems":1, "maxItems":5, "uniqueItems":true } }, "minProperties":1, "maxProperties":5, "required":[ "id", "name", "price" ] }

关键字说明

JOSN模式中常用的关键字(加粗字体为常用字段)

Untitled

声明JSON模式

由于JSON Schema本身就是JSON,所以当一些东西是JSON Schema或者只是JSON的任意一块时,并不总是很容易分辨。该

https://math.jianshu.com/math?formula=schema关键字用于声明某些内容是JSON Schema,

schema设置schema所使用的参照标准。包含它通常是一种很好的做法,尽管不是必需的。

{ "$schema": "<http://json-schema.org/schema#>" }

声明唯一标识符(不懂)

最佳做法是将$id属性包含为每个模式的唯一标识符。现在,只需将其设置为您控制的域中的URL,例如:

{ "$id": "<http://yourdomain.com/schemas/myschema.json>"}

type常见取值

Type其实就是JSON数据的基本数据类型,一般是有6种,加上null一共有7种:

Untitled


type:Object

示例:

{ "type":"object", "properties":{ "id":{ "description":"The unique identifier for a book", "type":"integer", "minimum":1 }, "price":{ "type":"number", "minimum":0, "exclusiveMinimum":true } }, "patternProperties":{ "^a":{ "type":"number" }, "^b":{ "type":"string" } }, "additionalProperties":{ "type":"number" }, "minProperties":1, "maxProperties":5, "required":[ "id", "name", "price" ] }

object类型有三个关键字:type(限定类型),properties(定义object的各个字段),required(限定必需字段)

Untitled

minProperties、maxProperties说明(用的不是很多)

这两个关键字的值都是非负整数。待校验的JSON对象中一级key的个数限制,minProperties指定了待校验的JSON对象可以接受的最少一级key的个数,maxProperties指定了待校验JSON对象可以接受的最多一级key的个数

patternProperties

正则表达式匹配json出现的属性,该JSON对象的每一个一级key都是一个正则表达式,用来匹配value值。

只有待校验JSON对象中的一级key,通过与之匹配的patternProperties中的一级正则表达式,对应的JSON Schema的校验,才算通过校验。例如,如果patternProperties对应的值如下:

在待校验JSON对象中,所有以S开头的key的value都必须是number,所有以I开头的一级key的value都必须是string。

{ "patternProperties": { "^S_": { "type": "number" }, "^I": { "type": "string" } } }


type:array

示例:

{ "$schema": "<http://json-schema.org/draft-04/schema#>", "title": "Product", "description": "A product from Acme's catalog", { "type":"array", "items":[ { "type":"string", "minLength":5 }, { "type":"number", "minimum":10 } ], "additionalItems":{ "type":"string", "minLength":2 }, "minItems":1, "maxItems":5, "uniqueItems":true }

array有三个单独的属性:items,minItems,uniqueItems:

Untitled

items

该关键字的值是一个有效的JSON Schema或者一组有效的JSON Schema。

{ "type": "array", "items": { "type": "string", "minLength": 5 } }

上面的JSON Schema的意思是,待校验JSON数组的元素都是string类型,且最小可接受长度是5。那么下面这个JSON数组明显是符合要求的,具体内容如下:["myhome", "green"]下面这个JSON数组明显不符合要求["home", "green"]

当该关键字的值是一组有效的JSON Schema时,只有待校验JSON数组的所有元素通过items的值中对应位置上的JSON Schema的校验,那么,整个待校验JSON数组才算通过校验。

这里需要注意的是:如果items定义的有效的JSON Schema的数量和待校验JSON数组中元素的数量不一致,那么就要采用“取小原则”。即,如果items定义了3个JSON Schema,但是待校验JSON数组只有2个元素,这时,只要待校验JSON数组的前两个元素能够分别通过items中的前两个JSON Schema的校验,那么,我们认为待校验JSON数组通过了校验。而,如果待校验JSON数组有4个元素,这时,只要待校验JSON数组的前三个元素能够通过items中对应的JSON Schema的校验,我们就认为待校验JSON数组通过了校验。例如,如果items的值如下:

{ "type":"array", "items":[ { "type":"string", "minLength":5 }, { "type":"number", "minimum":10 }, { "type":"string" } ] }

上面的JSON Schema指出了待校验JSON数组应该满足的条件,数组的第一个元素是string类型,且最小可接受长度为5,数组的第二个元素是number类型,最小可接受的值为10,数组的第三个元素是string类型。那么下面这两个JSON数组明显是符合要求的,具体内容如下:["green", 10, "good"]["helloworld", 11]下面这两个JSON数组却是不符合要求的,具体内容如下:["green", 9, "good"]//9小于minimum["good", 12]//good小于minLength

additionalItems

该关键字的值是一个有效的JSON Schema。

需要注意的是,该关键字只有在items关键字的值为一组有效的JSON Schema的时候,才可以使用,用于规定超出items中JSON Schema总数量之外的待校验JSON数组中的剩余的元素应该满足的校验逻辑。只有这些剩余的所有元素都满足additionalItems的要求时,待校验JSON数组才算通过校验。

可以这么理解,当items的值为一组有效的JOSN Schema的时候,一般可以和additionalItems关键字组合使用,items用于规定对应位置上应该满足的校验逻辑,而additionalItems用于规定超出items校验范围的所有剩余元素应该满足的条件。如果二者同时存在,那么只有待校验JSON数组同时通过二者的校验,才算真正地通过校验。

另外,需要注意的是,如果items只是一个有效的JSON Schema,那么就不能使用additionalItems,原因也很简单,因为items为一个有效的JSON Schema的时候,其规定了待校验JSON数组所有元素应该满足的校验逻辑。additionalItems已经没有用武之地了。

强调一下,省略该关键字和该关键字的值为空JSON Schema,具有相同效果。

{ "type": "array", "items": [ { "type": "string", "minLength": 5 }, { "type": "number", "minimum": 10 } ], "additionalItems": { "type": "string", "minLength": 2 } }

上面的JSON Schema的意思是,待校验JSON数组第一个元素是string类型,且可接受的最短长度为5个字符,第二个元素是number类型,且可接受的最小值为10,剩余的其他元素是string类型,且可接受的最短长度为2。那么,下面三个JSON数组是能够通过校验的,具体内容如下:["green", 10, "good"]["green", 11]["green", 10, "good", "ok"]下面JSON数组是无法通过校验的,具体内容如下:["green", 10, "a"]["green", 10, "ok", 2]

minItems、maxItems

这两个关键字的值都是非负整数。

指定了待校验JSON数组中元素的个数限制,minItems指定了待校验JSON数组可以接受的最少元素个数,而maxItems指定了待校验JSON数组可以接受的最多元素个数。

另外,需要注意的是,省略minItems关键字和该关键字的值为0,具有相同效果。而,如果省略maxItems关键字则表示对元素的最大个数没有限制。例如,如果限制一个JSON数组的元素的最大个数为5,最小个数为1,则JSON Schema如下:"minItems": 1,"maxItems": 5

uniqueItems

该关键字的值是一个布尔值,即boolean(true、false)。

当该关键字的值为true时,只有待校验JSON数组中的所有元素都具有唯一性时,才能通过校验。当该关键字的值为false时,任何待校验JSON数组都能通过校验。

另外,需要注意的是,省略该关键字和该关键字的值为false时,具有相同的效果。例如:"uniqueItems": true

contains

注意:该关键字,官方说明中支持,但是,有可能你使用的平台或者第三方工具不支持。所以,使用需谨慎。

该关键字的值是一个有效的JSON Schema。

只有待校验JSON数组中至少有一个元素能够通过该关键字指定的JSON Schema的校验,整个数组才算通过校验。

另外,需要注意的是,省略该关键字和该关键字的值为空JSON Schema具有相同效果。


type:string

示例

{ "$schema":"<http://json-schema.org/draft-04/schema#>", "title":"Product", "description":"A product from Acme's catalog", "type":"object", "properties":{ "ip":{ "type":"string", "pattern":"w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*" }, "host":{ "type":"phoneNumber", "pattern":"((d{3,4})|d{3,4}-)?d{7,8}(-d{3})*" }, "email":{ "type":"string", "format":"email" } }, "required":[ "ip", "host" ] }

Untitled

format该关键字的值只能是以下取值:date-time(时间格式)、email(邮件格式)、hostname(网站地址格式)、ipv4、ipv6、uri、uri-reference、uri-template、json-pointer。如果待校验的JSON元素正好是一个邮箱地址,那么,我们就可以使用format关键字进行校验,而不必通过pattern关键字指定复杂的正则表达式进行校验。


type:integer or number

示例

{ "$schema":"<http://json-schema.org/draft-04/schema#>", "title":"Product", "description":"A product from Acme's catalog", "type":"object", "properties":{ "price":{ "type":"number", "multipleOf":0.5, "maximum":12.5, "exclusiveMaximum":true, "minimum":2.5, "exclusiveMinimum":true } }, "required":[ "price" ] }

integer和number的区别,integer相当于Java中的int类型,而number相当于Java中的int或float类型。number 关键字可以描述任意长度,任意小数点的数字。

Untitled

multipleOf

该关键字的值是一个大于0的number,即可以是大于0的int,也可以是大于0的float。只有待校验的值能够被该关键字的值整除,才算通过校验。如果含有该关键字的JSON Schema如下{ "type": "integer", "multipleOf": 2 }2、4、6都是可以通过校验的,但是,3、5、7都是无法通过校验的,当然了,2.0、4.0也是无法通过校验的,但是,并不是因为multipleOf关键字,而是因为type关键字。如果含有multipleOf关键字的JSON Schema如下{ "type": "number", "multipleOf": 2.0 }2、2.0、4、4.0都是可以通过校验的,但是,3、3.0、3、3.0都是无法通过校验的。另外,需要注意的是,省略该关键字则不对待校验数值进行该项校验。

maximum

该关键字的值是一个number,即可以是int,也可以是float。该关键字规定了待校验元素可以通过校验的最大值。省略该关键字,即表示对待校验元素的最大值没有要求

exclusiveMaximum

该关键字的值是一个boolean。该关键字通常和maximum一起使用,当该关键字的值为true时,表示待校验元素必须小于maximum指定的值;当该关键字的值为false时,表示待校验元素可以小于或者等于maximum指定的值。需要注意的是,省略该关键字和该关键字的值为false,具有相同效果。例如:{ "type": "number", "maximum": 12.3, "exclusiveMaximum": true }

minimum、exclusiveMinimum

minimum、exclusiveMinimum关键字的用法和含义与maximum、exclusiveMaximum相似。唯一的区别在于,一个约束了待校验元素的最小值,一个约束了待校验元素的最大值。


type:boolean

对应着true或者false

{ "type":"object", "properties":{ "number":{ "type":"boolean" } } }

进阶

type:enum

该关键字的值是一个数组,该数组至少要有一个元素,且数组内的每一个元素都是唯一的。

如果待校验的JSON元素和数组中的某一个元素相同,则通过校验。否则,无法通过校验。

注意,该数组中的元素值可以是任何值,包括null。省略该关键字则表示无须对待校验元素进行该项校验。

{ "type":"object", "properties":{ "street_type":{ "type":"string", "enum":[ "Street", "Avenue", "Boulevard" ] } } }

{ "type":"object", "properties":{ "street_type":[ "Street", "Avenue", "Boulevard" ] } }

type:const

该关键字的值可以是任何值,包括null。如果待校验的JSON元素的值和该关键字指定的值相同,则通过校验。否则,无法通过校验。省略该关键字则表示无须对待校验元素进行该项校验。注意,该关键字部分第三方工具,并不支持

关键字:$ref

用来引用其他的schema示例:

{ "$schema": "<http://json-schema.org/draft-04/schema#>", "title": "Product set", "type": "array", "items": { "title": "Product", "type": "object", "properties": { "id": { "description": "The unique identifier for a product", "type": "number" }, "name": { "type": "string" }, "price": { "type": "number", "minimum": 0, "exclusiveMinimum": true }, "tags": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true }, "dimensions": { "type": "object", "properties": { "length": {"type": "number"}, "width": {"type": "number"}, "height": {"type": "number"} }, "required": ["length", "width", "height"] }, "warehouseLocation": { "description": "Coordinates of the warehouse with the product", "$ref": "<http://json-schema.org/geo>" } }, "required": ["id", "name", "price"] } }

关键字definitions

当一个schema写的很大的时候,可能需要创建内部结构体,再使用$ref进行引用,示列如下:

{ "type": "array", "items": { "$ref": "#/definitions/positiveInteger" }, "definitions": { "positiveInteger": { "type": "integer", "minimum": 0, "exclusiveMinimum": true } } }

关键字:allOf

该关键字的值是一个非空数组,数组里面的每个元素都必须是一个有效的JSON Schema。只有待校验JSON元素通过数组中所有的JSON Schema校验,才算真正通过校验。意思是展示全部属性,建议用requires替代,不建议使用,示例如下

{ "definitions":{ "address":{ "type":"object", "properties":{ "street_address":{ "type":"string" }, "city":{ "type":"string" }, "state":{ "type":"string" } }, "required":[ "street_address", "city", "state" ] } }, "allOf":[ { "$ref":"#/definitions/address" }, { "properties":{ "type":{ "enum":[ "residential", "business" ] } } } ] }

关键字:anyOf

该关键字的值是一个非空数组,数组里面的每个元素都必须是一个有效的JSON Schema。如果待校验JSON元素能够通过数组中的任何一个JSON Schema校验,就算通过校验。意思是展示任意属性,建议用requires替代和minProperties替代,示例如下:

{ "anyOf":[ { "type":"string" }, { "type":"number" } ] }

关键字:oneOf

该关键字的值是一个非空数组,数组里面的每个元素都必须是一个有效的JSON Schema。如果待校验JSON元素能且只能通过数组中的某一个JSON Schema校验,才算真正通过校验。不能通过任何一个校验和能通过两个及以上的校验,都不算真正通过校验。其中之一

{ "oneOf":[ { "type":"number", "multipleOf":5 }, { "type":"number", "multipleOf":3 } ] }

关键字:not

该关键字的值是一个JSON Schema。只有待校验JSON元素不能通过该关键字指定的JSON Schema校验的时候,待校验元素才算通过校验。非 * 类型

{ "not":{ "type":"string" } }

关键字:default

需要特别注意的是,type关键字的值可以是一个string,也可以是一个数组。如果type的值是一个string,则其值只能是以下几种:null、boolean、object、array、number、string、integer。如果type的值是一个数组,则数组中的元素都必须是string,且其取值依旧被限定为以上几种。只要带校验JSON元素是其中的一种,则通过校验。



我们项目如何集成JSON Schema

  1. 引入JSON Schema的依赖

<dependency><groupId>io.rest-assured</groupId><artifactId>json-schema-validator</artifactId><version>3.1.1</version></dependency>

  1. 添加两个工具包ReadJsonFile,JsonValidateUtilReadJsonFile:从/src/main/resources目录中读取json文件JsonValidateUtil:校验json数据是否符合schema约定的标准文件1:ReadJsonFile

`package com.mfw.flight.platform.server.util;

import com.fasterxml.jackson.databind.JsonNode; import com.github.fge.jackson.JsonNodeReader;

import java.io.*;

/**

  • @Author: sunshaokang

  • @Date: 2018/12/29 上午11:23 / public class ReadJsonFile { /*

    /**

    • 读取Json文件为JsonNode
    •  
    • @param filePath filePath为文件的绝对路径
    • @return */ public static JsonNode readJsonFileAsJsonNode(String filePath) { JsonNode instance = null; try { instance = new JsonNodeReader().fromReader(new FileReader(filePath)); } catch (IOException e) { e.printStackTrace(); } return instance; } }`
    • 读取Json文件为String json
    •  
    • @param filePath filePath为文件的相对于resources的路径
    • @return */ public static String readJsonFileAsString(String filePath) { filePath = ReadJsonFile.class.getResource(filePath).getPath(); String jsonStr = ""; try { File jsonFile = new File(filePath); FileReader fileReader = new FileReader(jsonFile); Reader reader = new InputStreamReader(new FileInputStream(jsonFile), "utf-8"); int ch = 0; StringBuffer sb = new StringBuffer(); while ((ch = reader.read()) != -1) { sb.append((char) ch); } fileReader.close(); reader.close(); jsonStr = sb.toString(); return jsonStr; } catch (IOException e) { e.printStackTrace(); return null; } }

文件2:JsonValidateUtil

`package com.mfw.flight.platform.server.util;

import com.fasterxml.jackson.databind.JsonNode; import com.github.fge.jackson.JsonLoader; import com.github.fge.jsonschema.core.report.ProcessingMessage; import com.github.fge.jsonschema.core.report.ProcessingReport; import com.github.fge.jsonschema.main.JsonSchemaFactory; import lombok.extern.slf4j.Slf4j; import org.junit.Test;

import java.io.IOException; import java.util.Iterator;

/**

  • @Author: sunshaokang
  • @Date: 2019/3/27 10:44 */

@Slf4j public class JsonValidateUtil { private final static JsonSchemaFactory factory = JsonSchemaFactory.byDefault();

/** * 校验JSON * * @param schema   json模式数据(可以理解为校验模板) * @param instance 需要验证Json数据 * @return */public static ProcessingReport validatorJsonSchema(String schema, String instance) throws IOException {    ProcessingReport processingReport = null;    JsonNode jsonSchema = JsonLoader.fromString(schema);    JsonNode jsonData = JsonLoader.fromString(instance);    processingReport = factory.byDefault().getValidator().validateUnchecked(jsonSchema, jsonData);    boolean success = processingReport.isSuccess();    if (!success){        Iterator<ProcessingMessage> iterator = processingReport.iterator();        while (iterator.hasNext()){            log.error(String.valueOf(iterator.next()));        }    }    return processingReport;}

}`

  1. 添加Json文件/src/main/resources/json目录下添加json文件

    image.png

  2. 编写测试类验证注意:ReadJsonFile.readJsonFileAsString(filePath)此方法中filePath为文件相对于resources目录的路径,以/开头。

@Test public void testschema() throws Exception { String data = ReadJsonFile.readJsonFileAsString("/json/testString.json"); String schema = ReadJsonFile.readJsonFileAsString("/json/testSchema.json"); ProcessingReport processingReport = validatorJsonSchema(schema, data); boolean success = processingReport.isSuccess(); System.out.println(success); // 如下方法可以用来接口自动化 // Assert.assertTrue(report.isSuccess()); }

  1. 针对response校验出参校验

response.then().assertThat().body(matchesJsonSchemaInClasspath("/json/flightChangeResponse.json"));

bak

matchesJsonSchemaInClasspath 是从 io.restassured.module.jsv.JsonSchemaValidator 这个类中静态导入的,并且推荐静态导入这个类中的所有方法 该方法中直接写json文件名即可

其中ProcessingReport对象中维护了一迭代器,如果执行失败(执行成功时没有信息),其提供了一些高级故障信息。每个错误可能包含以下属性:

  • level: 错误级别(应该就是error)
  • schema:引起故障的模式的所在位置的 URI
  • instance:错误对象
  • domain:验证域
  • keyword:引起错误的约束key
  • found:现在类型
  • expected:期望类型
©著作权归作者所有:来自51CTO博客作者mb607558ea4fef1的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. volatile关键字?MESI协议?指令重排?内存屏障?这都是啥玩意
  2. 面向对象、类和对象、封装---------私有private、this关键字
  3. Shell中打印匹配关键字的前后行 [echo、grep用法]
  4. transient关键字的作用以及几个疑问的解决
  5. 一文看懂 java 10 中 var 关键字(类型推断)!
  6. 4G LTE移动通信传输过程分析与仿真(一)
  7. 9.5private 和this关键字的用法
  8. C语言——C语言常用关键字总结(新手 还请不吝赐教)(一)
  9. 如何检查列表中的值是否存在文件每行中?

随机推荐

  1. Android的权限permission
  2. android 开发上传图片遇到返回 FileNotFo
  3. 11.时钟&计时器
  4. Android ListView(Selector 背景图片 全选
  5. Android碎片积累
  6. Android核心基础(五)
  7. 第12天android:短信发送+测试使用
  8. Android中NDK各版本下载
  9. Android(安卓)横竖屏幕切换
  10. Mac下获取android studio keystore的SHA1