美文网首页
python接口自动化-json结构体断言jsonschema

python接口自动化-json结构体断言jsonschema

作者: 疯子李 | 来源:发表于2023-12-22 00:27 被阅读0次

一、问题背景

我们编写自动化时通过断言取校验返回结果是否符合预期,通常只校验协议状态码httpstatus=200和业务返回体code=0,当对返回数据的要求提高时,如需要校验返回手机号是否符合大陆手机号,返回身份证是否合法等等,传统的断言无法完成。需要引入python第三方库jsonschema来完成返回json结构体的全字段断言,更好的保障业务。

二、常用断言介绍

jmeter

jmeter断言
  • json断言


    json断言
  • 响应断言


    响应断言
  • 自定义-beanshell断言


    beanshell断言

python/java原生

assert 1==1

unittest

assertEqual(arg1, arg2, msg=None)

java-testng

  • Assert
// 断言真假
Assert.assertTrue(true);
// 断言匹配,前一个参数是期望值,后一个参数是实际值
Assert.assertEquals(1, 1);

断言框架

三、什么是json

了解JSON Schema之前需要知道什么是json。
json是用于存储和交换数据的语法,是一种轻量级的数据交换格式。

使用场景
1)接口数据传输
2)序列化
3)配置文件

json与python对比

python json 说明
dict object 字典
list,tuple array 序列
str string 字符串
int,float number 数字类型
True true 布尔值True
False false 布尔值False
None null 空值

三、什么是jsonschema

JSON Schema 规范(中文版)
JSON Schema 是用于验证 JSON 数据结构的强大工具,Schema可以理解为模式或者规则。详细介绍见上面中文手册。

常用关键字介绍

关键字 说明 备注
type 类型 支持对象object、数组array、字符串string、整型integer、数字类型number包括整数浮点、布尔bollean、空null
properties 属性 序列
title 标题 注释的作用非必填
default 默认值 非必填
examples 示例 非必填
required 是否必传 必填字段,数组形式,如"required":["字段1","字段2","字段3"]
maximum 最大值 仅适用于integer或number
minimum 最小值 仅适用于integer或number
maxLength 最大长度 仅适用于string
minLength 最小长度 仅适用于string
maxProperties 最大属性数 用于object中有多少键值对
minProperties 最小属性数 用于object中有多少键值对
format 格式 draft7中支持,date日期 2018-11-13、 time时间 20:20:39+00:00、日期时间date-time 2018-11-13T20:20:39+00:00、邮箱email xx@xx.com、ip ipv4 xx.xx.xx、网址 uri www.xx.com
pattern 正则 常用于邮箱、身份证、手机号等
enum 枚举 常用于邮箱、身份证、手机号等
const 常量 固定值
uniqueItems 唯一元素 常用于数组,限制数组中每个元素都是唯一
items 元素 常用于数组,代表数组中的元素,对元素格式进行限制

四、怎么使用jsonschema

下面用个人信息的例子,涵盖主流关键字,并且进行测试,获取校验不通过时的对应报错

# -*- coding: utf-8 -*-
# @Time    : 2022/12/18 20:41
# @Author  : yanfa
# @File    : test_json_schema.py
# @Software: PyCharm
import jsonschema
import pytest
import logging
from jsonschema import Draft7Validator


class TestJsonSchema:
    # 模式
    schema = {
        # 类型
        "type": "object",
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "大陆居民信息详情",
        "description": "主要涉及身份、户籍等",
        "default": "这是默认值",
        "examples": [
            "例子1",
            "例子2"
        ],
        # 必传字段列表
        "required": [
            "name",
            "sex",
            "address"
        ],
        # 属性
        "properties": {
            "name": {
                "type": "string"
            },
            "year_for_days": {
                "type": "integer",
                "multipleOf": 365  # 倍数
            },
            "youth": {
                "type": "integer",
                "minimum": 14,  # 最小值
                "maximum": 35  # 最大值
            },
            "industry": {
                "type": "string",
                "minLength": 2,  # 最小长度
                "maxLength": 10  # 最大长度
            },
            "birthday": {
                "type": "string",
                "format": "date"  # 格式-日期
            },
            "email": {
                "type": "string",
                "format": "idn-email"  # 格式-邮箱
            },
            "url": {
                "type": "string",
                "format": "uri"  # 格式-网址
            },
            "ip": {
                "type": "string",
                "format": "ipv4"  # 格式-ip
            },
            "iphone": {
                "type": "string",
                "pattern": "^(+86)?-?1[3-9]d{9}$"  # 正则 手机号
            },
            "sex": {
                "type": "string",
                # 枚举
                "enum": [
                    "男",
                    "女"
                ]
            },
            "nationality": {
                "type": "string",
                "const": "中国"  # 常量
            },
            "car_info": {
                "type": "object",
                "minProperties": 2,  # 最小属性个数
                "maxProperties": 3,  # 最大属性个数
                "properties": {
                    "number": {
                        "type": "string"
                    },
                    "color": {
                        "type": "string"
                    },
                    "type": {
                        "type": "string"
                    }
                }
            },
            "child_id": {
                "type": "array",
                "uniqueItems": True,  # 元素是否唯一
                # 数组元素
                "items": {
                    "type": "string"
                }
            }
        },
        # 嵌套
        "address": {
            "type": "object",
            "properties": {
                "detail_address": {
                    "type": "string"
                },
                "city": {
                    "type": "string"
                },
                "province": {
                    "type": "string"
                }
            }
        }
    }
    # 原始json示例
    org_instance = {
        "name": "李四",
        "year_for_days": 365,  # 出生天数
        "youth": 30,  # 青年人年龄
        "industry": "建筑工",  # 行业
        "birthday": "2002-10-01",  # 生日
        "email": "88888888@qq.com",  # 个人邮箱
        "url": "http://example.com",  # 个人网址
        "ip": "10.10.26.40",  # 个人ip地址
        "iphone": "18988888888",  # 大陆手机号
        "sex": "男",  # 性别
        "nationality": "中国",  # 国籍
        "car_info": {"number": "1234", "color": "black", "type": "suv"},  # 车辆信息
        "child_id": ["66666666", "88888888"],  # 儿女身份证
        "address": {  # 地址
            "detail_address": "科兴科学园66栋",
            "city": "深圳市",
            "province": "广东省"
        }
    }

    def validate_case(self):
        """验证是否符合
        输入原json
        输出是否符合
        """
        try:
            # 新建format的验证器类。
            validator_cls = jsonschema.validators.validator_for(self.schema)
            # 验证器实现可以提供一个配置选项来启用format作为断言而不仅仅是注释的功能
            validator = validator_cls(self.schema, format_checker=jsonschema.FormatChecker())    
            # 使用验证器的validate函数来验证data是否符合schema
            validator.validate(self.org_instance)
            logging.info("JSON实例符合JSON Schema")
        except jsonschema.exceptions.ValidationError as err:
            logging.error("JSON实例不符合JSON Schema:", err)

    def test_normal(self):
        """正常情况"""
        self.validate_case()

    def test_type(self):
        """类型检查
        jsonschema.exceptions.ValidationError: '365' is not of type 'integer'
        """
        self.org_instance["year_for_days"] = '365'
        self.validate_case()

    def test_required(self):
        """必传检查
        jsonschema.exceptions.ValidationError: 'address' is a required property
        """
        self.org_instance.pop('address')
        self.validate_case()

    def test_multipleOf(self):
        """倍数检查
        jsonschema.exceptions.ValidationError: 370 is not a multiple of 365
        """
        self.org_instance["year_for_days"] = 370
        self.validate_case()

    def test_minimum_maximum(self):
        """最大最小值检查
        jsonschema.exceptions.ValidationError: 13 is less than the minimum of 14
        jsonschema.exceptions.ValidationError: 36 is greater than the maximum of 35
        """
        # 青年人区间为14-35,设置为13,36
        # self.org_instance["youth"] = 13
        self.org_instance["youth"] = 36
        self.validate_case()

    def test_format_for_date(self):
        """格式检查-日期
        jsonschema.exceptions.ValidationError: '123' is not a 'date'
        """
        self.org_instance["birthday"] = "123"
        self.validate_case()

    def test_format_for_email(self):
        """格式检查-邮箱
        jsonschema.exceptions.ValidationError: '2222' is not a 'idn-email'
        """
        self.org_instance["email"] = "2222"
        self.validate_case()

    def test_format_for_uri(self):
        """格式检查-网址"""
        # todo 还是有问题
        self.org_instance["url"] = "哈哈"
        self.validate_case()

    def test_format_for_ipv4(self):
        """格式检查-ip
        jsonschema.exceptions.ValidationError: '1234' is not a 'ipv4'
        """
        self.org_instance["ip"] = "1234"
        self.validate_case()

    def test_format_for_pattern(self):
        """正则检查-手机号
        jsonschema.exceptions.ValidationError: '12346789' does not match '^(\\+86)?-?1[3-9]\\d{9}$'
        """
        self.org_instance["iphone"] = "12346789"
        self.validate_case()

    def test_enum(self):
        """枚举检查-性别
         jsonschema.exceptions.ValidationError: '中性' is not one of ['男', '女']
         """
        self.org_instance["sex"] = "中性"
        self.validate_case()

    def test_const(self):
        """常量检查-国籍
        jsonschema.exceptions.ValidationError: '中国' was expected
        """
        self.org_instance["nationality"] = "美国"
        self.validate_case()

    def test_minProperties_maxProperties(self):
        """对象属性个数检查-国籍
        jsonschema.exceptions.ValidationError: {'number': '1234'} does not have enough properties
        jsonschema.exceptions.ValidationError: {'number': '1234', 'color': 'black', 'type': 'suv', 'length': '3'} has too many properties
        """
        # 删除一个属性,最低要求2个属性,目前只传一个属性
        # self.org_instance["car_info"].pop("color")
        # 新增一个属性,最高要求3个属性,目前四个属性
        self.org_instance["car_info"]["length"] = "3"
        self.validate_case()

    def test_items(self):
        """列表元素类型检查-子女身份证
        jsonschema.exceptions.ValidationError: 888999 is not of type 'string'"""
        # 模式中身份证为字符串,这里传数字
        self.org_instance["child_id"][0] = 888999
        self.validate_case()

    def test_uniqueItems(self):
        """列表元素唯一性检查-子女身份证
         jsonschema.exceptions.ValidationError: ['66666666', '66666666'] has non-unique elements"""
        # 修改第二个元素与第一个元素相同
        self.org_instance["child_id"][1] = "66666666"
        self.validate_case()

    def test_minLength_maxLength(self):
        """属性长度检查-详细地址
        jsonschema.exceptions.ValidationError: '测' is too short
        jsonschema.exceptions.ValidationError: '资深高级专业无敌营养设计师' is too long
        """
        # 修改长度小于5
        # self.org_instance["industry"] = "测"
        self.org_instance["industry"] = "资深高级专业无敌营养设计师"
        self.validate_case()


if __name__ == '__main__':
    # 执行测试用例
    pytest.main([
        '/Users/yanfademac_pro/PycharmProjects/myProject/data_deal/test_json_schema.py::TestJsonSchema',
        '-s'])

相关文章

  • 使用jsonschema校验json数据

    jsonschema用来标记和校验json数据,可在自动化测试中验证json的整体结构和字段类型 首先,了解一下j...

  • 接口自动化中的jsonSchema及契约测试

    目录 场景介绍:接口自动化及契约测试 jsonschema介绍 契约测试实现步骤及Demo jsonschema编...

  • 还在用equals来做对象断言么?

    断言需求分析 在HTTP接口自动化测试时,如果接口返回是JSON格式的结果,通常可以用Sting比较的方式进行断言...

  • go得快(1)

    接口 多态 结构体里的tag 类型断言 空接口 接口的三个规则

  • JSON数据转C++结构体

    JSON数据自动生成C++结构体 JSON数据自动生成C++结构体背景nlohmann/json基础Python自...

  • Go语言接口知识点2 和 别名

    接口的断言 1. 如果结构体实现了某个接口你那么就可以使用接口类型来保存结构体变量, 那么该变量只能访问接口中的方...

  • 接口自动化测试---通用JSON解析算法

    JSON格式的数据在http接口的自动化测试中是一种常见的数据结构,在接口自动化脚本里解析JSON返回结果,验证数...

  • 18 Golang结构体详解(四)

    结构体和Json相互转换 当Golang要为App或者小程序提供Api接口数据时,涉及到结构体和Json之间的相互...

  • 接口契约测试

    接口断言引入契约校验目录: 一.背景二.校验原则三.快速使用1、python类契约使用2、json契约使用3、py...

  • 使用JSONSchema断言

    对于复杂的JSON结构,虽然可以使用JSONPath快速提取相应的值。然而对于JSON响应的整体结构和各字段类型,...

网友评论

      本文标题:python接口自动化-json结构体断言jsonschema

      本文链接:https://www.haomeiwen.com/subject/ruaxndtx.html