9:JSONSchema

一、什么是 JSONSchema?

JSONSchema 是 JSON 数据的「规则说明书 + 校验器」

我们做接口自动化时,接口返回 JSON 格式数据,经常要校验:

  1. 返回字段有没有缺失(比如少了 code、data)
  2. 字段数据类型是否正确(code 是字符串、id 是数字,不能返回布尔 / 空)
  3. 字符串长度、数字范围、数组元素格式是否合规

**总结:**JSONSchema作用:

提前定义 JSON 规范,用代码校验返回数据

来确定数据是否符合约定格式,广泛用于接口自动化测试、前后端联调参数校验。

1.1 安装依赖(固定版本避免报错)

复制代码
# 统一版本4.23.0,防止新版本API变动
pip install jsonschema==4.23.0

安装成功后即可在 Python 代码导入校验函数。


二、JSONSchema 核心关键字

JSONSchema 本身是一个 JSON 字典结构,通过固定关键字约束数据

下面逐个拆解高频关键字:

2.1 type:限定字段数据类型

type 支持 7 种原生 JSON 类型,对应关系:

type 取值 含义 示例数据
string 字符串 "SUCCESS"、"123"
integer 纯整数 1099(不能带小数)
number 数字 (整数 + 浮点) 203.14
boolean 布尔 true/false
object JSON 对象({} 包裹) {"name":"张三"}
array JSON 数组(\[\] 包裹) [1,2,3]
null 空值 null

示例代码:基础对象类型校验

python 复制代码
from jsonschema.validators import validate

# 1. 定义校验规则schema(规则说明书)
schema = {
    "type": "object", # 根节点整体必须是对象{}
    "properties": { # 定义对象里面所有字段的规则
        "username": {"type": "string"}, # username必须是字符串
        "age": {"type": "integer"} # age必须是整数
    }
}

# 2. 待校验的JSON数据(接口返回数据)
right_data = {"username": "小明", "age": 18}
wrong_data = {"username": 123, "age": "十八"} # 类型全错

# 3. 执行校验,符合规则无报错,不符合直接抛异常
validate(instance=right_data, schema=schema)
# validate(instance=wrong_data, schema=schema) # 打开此行会触发校验失败报错

json转JSONSchema太麻烦?使⽤现有⼯具⾃动转换:json转jsonschema工具

注意:⼯具不是万能的,结果可能存在错误。

工具遇到安全问题无法访问需要无视警告继续访问

2.2 required:必填字段约束

required是列表格式,填写字段名,代表这些字段必须存在,缺字段直接校验失败。

python 复制代码
schema = {
    "type": "object",
    "required": ["code", "errMsg", "data"], # code、errMsg、data三个字段缺一不可
    "properties": {
        "code": {"type": "string"},
        "errMsg": {"type": "string"},
        "data": {"type": ["array", "null"]} # data可以是数组或者null空值
    }
}

# 缺了data字段,校验报错
err_json = {"code": "SUCCESS", "errMsg": ""}
# validate(instance=err_json, schema=schema)

2.3 properties:对象字段规则配置

properties用来逐个定义对象内每个字段的校验规则,只约束类型,不代表字段必填(必填要配合 required)。

2.4 数字约束:minimum/maximum(数值范围)

针对integer/number类型,限定数字最大、最小值:

  • minimum:大于等于该值
  • exclusiveMinimum:严格大于(不能等于)
  • maximum:小于等于该值
  • exclusiveMaximum:严格小于
python 复制代码
schema = {
    "type": "object",
    "properties": {
        "age": {
            "type": "integer",
            "minimum": 0,    # 年龄≥0
            "maximum": 120  # 年龄≤120
        }
    }
}

2.5 字符串约束:pattern 正则匹配

pattern通过正则表达式约束字符串格式(手机号、邮箱、账号格式校验必备)

python 复制代码
schema = {
    "type": "object",
    "properties": {
        "phone": {
            "type": "string",
            "pattern": "^1[3-9]\\d{9}$" # 国内11位手机号正则
        }
    }
}

2.6 数组约束:items/minItems/maxItems/uniqueItems

数组array专属关键字:

  • items:约束数组里每一个元素的格式
  • minItems/maxItems:数组最少 / 最多有几个元素
  • uniqueItems: true:数组内元素不能重复
python 复制代码
schema = {
    "type": "object",
    "properties": {
        "tag_list": {
            "type": "array",
            "minItems": 1,    # 数组最少1个元素
            "maxItems":5,     # 最多5个元素
            "uniqueItems":True,# 元素不能重复
            "items": {"type":"string"} # 数组里每个元素必须是字符串
        }
    }
}

2.7 对象进阶:additionalProperties 禁止多余字段

默认 JSON 对象可以随便加额外字段,additionalProperties:false 表示不允许出现 properties 没定义的字段(严格接口返回校验)

python 复制代码
schema = {
    "type": "object",
    "additionalProperties": False, # 不能出现name、age以外的字段
    "properties": {
        "name": {"type":"string"},
        "age": {"type":"integer"}
    }
}
# 多了sex字段,校验失败
extra_data = {"name":"小红","age":20,"sex":"女"}
# validate(instance=extra_data,schema=schema)

2.8 对象进阶:min/maxProperties 限制 JSON 键值对数量

minProperties:限制 JSON 对象最少拥有的键值对(属性)数量

实际属性数 < 设定值 → 校验失败

maxProperties:限制 JSON 对象最多拥有的键值对(属性)数量

实际属性数 > 设定值 → 校验失败

作用于 type:object 类型;与 required(必填字段)是两套规则:

  • required:管控必须存在哪些 key
  • min/maxProperties:管控key 总个数范围
python 复制代码
from jsonschema import validate

# 1、JSON Schema规则:单个博客对象,属性数量必须在7~9个之间
blog_schema = {
    "type": "object",
    "minProperties": 7,   # 最少7个字段
    "maxProperties": 9,   # 最多9个字段
    "properties": {
        "id": {"type": "number"},
        "title": {"type": "string"},
        "content": {"type": "string"},
        "userId": {"type": "number"},
        "deleteFlag": {"type": "number"},
        "createTime": {"type": "string"},
        "updateTime": {"type": "string"},
        "loginUser": {"type": "boolean"}
    }
}

# 样例1:正常数据(一共8个字段,7≤8≤9,校验通过)
normal_data = {
    "id": 5,
    "title": "自动化测试创建",
    "content": "##在这里写下一篇博客",
    "userId": 4,
    "deleteFlag": 0,
    "createTime": "2026-05-23 23:35",
    "updateTime": "2026-05-23T15:35:01.000+00:00",
    "loginUser": False
}

# 样例2:字段只有5个 < minProperties=7,校验报错
less_data = {
    "id": 5,
    "title": "自动化测试创建",
    "content": "##在这里写下一篇博客",
    "userId": 4,
    "deleteFlag": 0
}

# 执行校验
validate(instance=normal_data, schema=blog_schema)
print("✅ 正常数据校验通过")
# validate(instance=less_data, schema=blog_schema) #放开此行会抛出:属性数量不足异常

2.9 dependentRequired 设置 "属性依赖" :

设置 "属性依赖" 规则: 如果 A 属性出现了,那么 B 属性 必须也出现,否则校验不通过。

比如:creditCard(信用卡号)与 billingAddress(账单地址) 两个必须一起出现,不能只填一个。

python 复制代码
from jsonschema import validate, ValidationError

# JSON Schema 规则
schema = {
    "type": "object",
    "properties": {
        "creditCard": {"type": "string"},
        "billingAddress": {"type": "string"}
    },
    "dependentRequired": {
        "creditCard": ["billingAddress"]
    }
}

# 合法数据
valid_data = {
    "creditCard": "6222123456789012",
    "billingAddress": "广东省深圳市南山区"
}

# 非法数据(只填信用卡,没有地址)
invalid_data = {
    "creditCard": "6222123456789012"
}

# 校验合法数据
try:
    validate(instance=valid_data, schema=schema)
    print("✅ 合法数据:校验通过")
except ValidationError as e:
    print("❌ 错误:", e.message)

# 校验非法数据
try:
    validate(instance=invalid_data, schema=schema)
    print("✅ 合法数据:校验通过")
except ValidationError as e:
    print("❌ 错误:", e.message)

三、实战案例:接口返回 JSON 完整校验(博客列表接口)

3.1 原始接口返回 JSON 结构

python 复制代码
{
  "code": "SUCCESS",
  "errMsg": "",
  "data": [
    {
      "id": 1,
      "title": "Python入门",
      "content": "学习JSONSchema",
      "userId": 1001,
      "deleteFlag": 0,
      "createTime": "2025-01-01",
      "updateTime": "2025-01-02",
      "loginUser": false
    }
  ]
}

3.2 手写对应 JSONSchema 规则 + 完整可运行 Python 代码

python 复制代码
import requests
from jsonschema.validators import validate

# 1. 定义整套接口返回的校验规则schema
blog_schema = {
    "type": "object", # 整个返回体是对象
    "required": ["code", "errMsg", "data"], # 三个字段必须存在
    "additionalProperties": False, # 不能多出其他字段
    "properties": {
        "code": {"type": "string"}, # 状态码字符串
        "errMsg": {"type": "string"}, # 错误提示字符串
        "data": {
            "type": "array", # data是数组
            "items": { # 数组里每一项是博客对象
                "type": "object",
                "required": ["id","title","content","userId","deleteFlag","createTime","updateTime","loginUser"],
                "additionalProperties":False,
                "properties": {
                    "id": {"type": "number"},
                    "title": {"type": "string"},
                    "content": {"type": "string"},
                    "userId": {"type": "number"},
                    "deleteFlag": {"type": "number"},
                    "createTime": {"type": "string"},
                    "updateTime": {"type": "string"},
                    "loginUser": {"type": "boolean"}
                }
            }
        }
    }
}

# 2. 调用接口获取真实返回数据
url = "http://8.137.19.140:9090/blog/getList"
headers = {
    "user_token_header": "eyJhbciOiJIUzI1NiJ9.eyJpZCI6MSwxNzkwNDc1NTk5NjE0OWFuY2hl"
}
res = requests.get(url=url, headers=headers)
resp_json = res.json()

# 3. 执行校验
try:
    validate(instance=resp_json, schema=blog_schema)
    print("✅ JSON格式完全符合规范,校验通过!")
except Exception as e:
    print(f"❌ 校验失败,错误详情:{e.message}")

四、懒人技巧:JSON 自动转 JSONSchema 工具

手动写 schema 繁琐,推荐在线自动生成工具:

https://tooltt.com/json2schema/

  1. 粘贴接口返回的 JSON 数据,一键生成基础 schema
  2. 重要提醒:工具生成结果需要二次修改(手动补充 required 必填、数值范围、正则等约束),不能直接拿来用。

五、自动化测试落地小技巧

  1. 用例分层:把每个接口的 schema 单独存为字典 / JSON 文件,测试用例直接读取,方便统一维护
  2. 异常捕获:try-except 捕获 validate 异常,测试报告输出详细错误信息(哪个字段类型错误、缺哪个必填项)
  3. 版本锁定 :安装固定jsonschema==4.23.0,避免库升级后 API 改动导致旧代码报错

六、常见踩坑总结(小白必看)

  1. integer 和 number 区别:integer 只能整数,number 支持整数 + 小数,不要混用
  2. 布尔值小写:JSON 布尔是true/false(小写),不是 Python 的 True/False(JSON 数据规范)
  3. required 字段写错名字:字段名大小写敏感,errmsg和errMsg是两个不同字段
  4. 空值 null:字段允许为空写"type":"string","null",代表字符串或 null 都合法
相关推荐
学测绘的小杨7 小时前
CompassFusion:一个从 GNSS 到 GNSS/INS 组合导航的独立工程包
python
zzzzzz31013 小时前
当产品经理说这个很简单:我用Python自动化处理奇葩需求的实战指南
python·pycharm·产品经理
雪隐14 小时前
个人电脑玩AI-06让5060 Ti给你打工——不光能画画,Qwen3-TTS还能学人说话,连我老板都信了!
人工智能·后端·python
兵慌码乱1 天前
面向桌面端的资产管理系统分层架构设计与核心模块实现
python·系统架构·sqlite·pyqt5·数据库设计·桌面应用开发·mvc架构
hboot1 天前
AI工程师第三课 - 机器学习基础
python·scikit-learn·kaggle
顾林海1 天前
Agent入门阶段-编程基础-Python:流程控制
python·agent·ai编程
呱呱复呱呱1 天前
Django CBV 源码解读:一个请求是怎么找到你的 get() 方法的
python·django
曲幽2 天前
刚部署的 LibreTranslate 频频翻车?我掏出了 20 年前的 StarDict 词典,用 FastAPI 搭了个本地词典翻译 API
python·fastapi·web·translate·goldendict·libretranslate·stardict·pystardict
荣码2 天前
用Streamlit给AI应用套个界面,10行代码出Web页面
java·python
兵慌码乱2 天前
基于Python+PyQt5+SQLite的药房管理系统实现:事务一致性与界面解耦全流程解析
python·sqlite·信号与槽·pyqt5·数据库设计·桌面应用开发·事务处理