likes
comments
collection
share

利用 Pytest 和 Schema 断言测试 JSON 数据格式

作者站长头像
站长
· 阅读数 1

前言

笔者测试过程中,接到这样一个测试任务,接口进行重构之后,需要测试同学来验证数据的结构和类型,以防因某个字段被删除或者类型被更改,造成隐藏问题出现的概率增加。那该如何验证数据结构和类型呢?带着这个问题,我们一起探索。

JSON Schema

前言中提到的问题,就需要使用JSON Schema来解决。那到底什么是JSON Schema,又该如何使用呢?

官方文档直达

什么是JSON Schema

JSON Schema 是一种用于验证和描述 JSON 数据结构的语言。它提供了一种标准化的规范方法,可以定义 JSON 数据的结构、数据类型以及相关约束条件。

JSON Schema 的基本语法

JSON Schema 使用 JSON 对象来表示数据结构和约束规则。以下是一些常见的 JSON Schema 关键字:

  • $schema:指定所使用的 JSON Schema 规范版本。
  • type:指定数据的类型,如字符串、数字、布尔值等。
  • properties:定义对象属性及其对应的约束规则。
  • required:指定必需的属性。
  • enum:定义枚举值列表。
  • pattern:使用正则表达式验证字符串格式。
  • minimummaximum:定义数值的最小值和最大值。
  • format:定义特定的数据格式,如日期、时间等。

演示案例

我们看这个示例,演示如何使用 JSON Schema 验证用户提交的表单数据:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "email": {
      "type": "string",
    },
    "age": {
      "type": "integer",
      "minimum": 18
    }
  },
  "required": ["name", "email"]
}

在上述示例中,我们定义了一个包含 nameemailage 属性的对象,并指定了它们的类型和必需性。

我们来测试一下:

from jsonschema import validate

x = {
    "name": "aomaker",
    "age": 2,
    "email": "111"
}
schema = {
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "age": {
      "type": "integer",
      "minimum": 18
    }
  },
  "required": ["name", "email"]
}

validate(x, schema)

这段代码中,x数据中给定age值为2,但是schema中要求age最小值为18,应该会校验不通过。执行发现果然报错:

jsonschema.exceptions.ValidationError: 2 is less than the minimum of 18

我们将age的值设置为大于等于18,即可校验通过。

这样我们将用户提交的数据与以上 JSON Schema 进行验证,我们就可以确保数据的合法性,并及时反馈给用户有关错误或缺失的信息。

你以为到这里就万事大吉了吗?如果响应数据有很多字段,已不是一个个写Schema会变得很困难,有种想放弃的感觉。幸好有genson.

genson

genson 是一个 Python 库,它用于生成符合 JSON Schema 规范的模式(schema)。genson 通过分析现有的 JSON 数据,自动生成相应的 JSON Schema。

安装

使用前,首先需要安装,安装很简单,执行下面这段命令即可:

pip install genson

SchemaBuilder

SchemaBuilder 是 Genson 库中用于构建 JSON Schema 的类。它通过添加对象、属性等元素来构建 JSON Schema 对象,并使用 to_schema 方法将其转换为 JSON 格式。

用法

add_object(obj: Any) -> 'SchemaBuilder'

添加一个包含数据的任意 Python 对象,例如字典、列表或自定义类。这个方法会根据传入的数据生成相应的 JSON Schema。

from genson import SchemaBuilder

builder = SchemaBuilder()
builder.add_object({'name': 'John', 'age': 25})
schema = builder.to_schema()
print(schema)
# 输出: {"type": "object", "properties": 
        {"name": {"type": "string"}, "age": {"type": "integer"}}, 
        "required": ["age", "name"]}

add_property(name: str, value: Any) -> 'SchemaBuilder'

添加一个属性到当前正在构建的对象中。该方法接收两个参数,name 表示属性名,value 表示属性值。添加属性后可以使用 add_object 方法继续往内部添加数据。

from genson import SchemaBuilder

builder = SchemaBuilder()
builder.add_property('name', 'John')
builder.add_property('age', 25)
schema = builder.to_schema()
print(schema)
# 输出: {"type": "object", "properties": 
        {"name": {"type": "string"}, "age": {"type": "integer"}}, 
        "required": ["name", "age"]}

to_schema() -> Dict[str, Any]

将构建好的 JSON Schema 转换为 Python 字典格式。

from genson import SchemaBuilder

builder = SchemaBuilder()
builder.add_object({'name': 'John', 'age': 25})
schema = builder.to_schema()
print(type(schema))  # 输出: <class 'dict'>

这些是常用的 SchemaBuilder 方法和用法。

有了这个类就方便多了,我们可以通过该类实现一个自动生成jsonschema校验语法。

实现案例

from genson import SchemaBuilder

def genson(data: dict = None):
    """
    return schema data
    """

    builder = SchemaBuilder()
    builder.add_object(data)
    to_schema = builder.to_schema()
    return to_schema

这段代码,在函数内部,我们创建了一个 SchemaBuilder 对象 builderSchemaBuilder 用于构建 JSON Schema 对象。

接下来,我们使用 add_object 方法将参数 data 添加到 builder 中。这会根据传入的数据生成相应的 JSON Schema。

最后,我们调用 to_schema 方法将 builder 转换为 JSON Schema 对象,并将结果存储在 to_schema 变量中。

最后,我们将生成的 JSON Schema 对象作为函数的返回值返回。

通过调用这个 genson 函数并传入一个字典对象,你将获得该字典数据对应的 JSON Schema。

x = {
    "name": "aomaker",
    "age": 18,
    "email": "111@qq.com"
}
schema = genson(x)

print(schema)

这些这段代码,可以看到我们期望的结果:

{'$schema': 'http://json-schema.org/schema#', 'type': 'object', 'properties': {'name': {'type': 'string'}, 'age': {'type': 'integer'}, 'email': {'type': 'string'}}, 'required': ['age', 'email', 'name']}

pytest增加断言Schema

def assert_schema(schema, response):
    """
    Assert JSON Schema
    """
    try:
        validate(instance=response, schema=schema)
    except ValidationError as msg:
        raise AssertionError

代码定义了一个名为 assert_schema 的函数,用于验证 JSON 数据是否符合给定的 JSON Schema。

这个函数接受两个参数:

  • schema:表示要验证的 JSON Schema,通常是一个字典或从 JSON 文件加载的对象。
  • response:表示要验证的 JSON 数据,通常是从 API 响应中获取的数据。

函数的主要逻辑是使用 validate 函数来比较 responseschema 是否匹配。如果不匹配,将引发 ValidationError 异常。

测试一下:

schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "integer"}
    },
    "required": ["name", "age"]
}

response = {
    "name": "John Doe",
    "age": 25
}

# 调用 assert_schema 函数进行验证
assert_schema(schema, response)

如果 API 响应数据不符合 JSON Schema,assert_schema 函数将引发断言错误,并显示详细的验证错误消息。

最后

genson虽然可以帮助我们快速生成Scheam,但预期结果还是要手动进行维护的。当然,后续我们其实可以在做接口自动化时,在接口被调用的时候自动存储到数据库,然后持续维护这个表的数据即可,后续想办法实现一下。JSON Schema已经可以解决我们前言中提到的问题了。JSON Schema 可以帮助我们定义和验证 JSON 数据的结构、类型和约束条件,确保数据的有效性和一致性,提高数据交互的质量和可靠性。