接口自动化全量字段校验

本文介绍了接口自动化全量字段校验的重要性,背景是为了解决接口返回数据结构不一致的问题。文章详细讲解了如何使用契约定义(支持Python类契约和JSON契约)进行校验,包括基本匹配规则(如值匹配、类型匹配、数组类型匹配等)、复杂规则匹配以及异常场景匹配,并提供了配合unittest+requests的使用方法。此外,还强调了异常匹配场景过多意味着接口数据格式不规范。
摘要由CSDN通过智能技术生成

目录

前言:

一.背景

二.校验原则

三.快速使用

安装:

1.python 类契约使用

2.json 契约使用

3.python 类契约转 json 契约

4.根据响应结果自动生成 json 契约

说明:

四.基本匹配规则

1. Matcher 类

校验规则:值匹配

2. Like 类

校验规则:类型匹配

3. EachLike 类

校验规则:数组类型匹配

4. Term 类

校验规则:正则匹配

5. Enum 类

校验规则:枚举匹配

五.复杂规则匹配

1.{ {}}格式

2.[[]] 格式

3.{[]}格式

4.Like-Term 嵌套

5.Like-Matcher 嵌套

说明:

六.异常场景匹配

1.null 匹配

2.{}匹配

3.json 格式字符串匹配

4.key 不存在匹配

5.多类型匹配

6.非强制字段匹配

注意:异常匹配场景越多,代表接口数据格式越不规范

七.配合 unittest+requests 使用

八.优点总结


前言:

接口自动化全量字段校验是一种对接口进行安全性评估的测试方法。它主要针对接口的全量字段进行校验,以确保接口的安全性和稳定性。

一.背景

公司前端吐槽后台接口有时会更改返回的数据结构,返回的字段名与字段类型与接口文档不一致,希望有一个快速检测接口返回数据的所有字段名与字段类型的方法

以下方数据为例,要校验 data 数组中 dict 结构中的字段名与字段类型,可以写脚本遍历数据,但是由于每个接口返回的数据结构可能不一致,可能需要针对每个接口做不同的逻辑,所以需要一个比较通用的校验方法

{
    "msg": "success",
    "code": 0,
    "data": [{
            "type_id": 249,
            "name": "王者荣耀",
            "order_index": 1,
            "status": 1,
            "subtitle": " ",
            "game_name": "王者荣耀"
        }, {
            "type_id": 250,
            "name": "绝地求生",
            "order_index": 2,
            "status": 1,
            "subtitle": " ",
            "game_name": "绝地求生"
        }, {
            "type_id": 251,
            "name": "刺激战场",
            "order_index": 3,
            "status": 1,
            "subtitle": " ",
            "game_name": "刺激战场"
        }
    ]
}

​在研究了契约测试后,抽取pact-python部分代码,实现:自定义接口返回数据格式 (【契约定义】)-实际响应数据格式校验 (【契约校验】) 的功能

备注:这里的【契约】等同于接口响应数据结构


二.校验原则

1.实际返回字段名要严格等于或者含契约定义字段名(根据不同匹配模式来确定)
2.字段值可以值相等或类型相等

目标:对返回数据进行全量 (字段名 - 值/类型) 校验
契约定义方式:支持 python 类契约和 json 契约


三.快速使用

安装:

pip install pactverify

1.python 类契约使用

from pactverify.matchers import Matcher, Like, EachLike, Enum, Term, PactVerify

# 定义契约格式
expect_format = Matcher({
    'code': 0,  # code key存在,值相等,code==0
    'msg': 'success',  # msg key存在,值相等,msg=='success'
    # [{}]结构
    'data': EachLike({
        "type_id": 249,  # type_id key存在,值类型相等,type(type_id) == type(249)
        "name": "王者荣耀",  # name key存在,值类型相等,type(name) == type("王者荣耀")
    }),
    'type': Enum([11,22]),
    'list': EachLike(11,minimum=2)
})

# 实际返回数据
actual_data = {
    "msg": "success",
    "code": 1,
    'type': 12,
    "data": [{
        # type_id类型不匹配
        "type_id": '249',
        "name": "王者荣耀"
    }, {
        # 缺少name
        "type_id": 250,
    }, {
        # 比契约定义多index字段
        "type_id": 251,
        "name": "刺激战场",
        "index": 111
    }
    ],
    'list': [11]
}
# hard_mode默认为true,hard_mode = True时,实际返回key必须严格等于预期key;hard_mode = False时,实际返回key包含预期key即可
mPactVerify = PactVerify(expect_format, hard_mode=True)
# 校验实际返回数据
mPactVerify.verify(actual_data)
# 校验结果  False
print(mPactVerify.verify_result)
''' 校验错误信息
错误信息输出actual_key路径:root.data.0.name形式
root为根目录,dict类型拼接key,list类型拼接数组下标(从0开始)
{   
    # 实际key少于预期key错误
    'key_less_than_expect_error': ['root.data.1.name'],
    # 实际key多与预期key错误,只在hard_mode = True时才报该错误
    'key_more_than_expect_error': ['root.data.2.index'],
    # 值不匹配错误
    'value_not_match_error': [{
            'actual_key': 'root.code',
            'actual_value': 1,
            'expect_value': 0
        }
    ],
    # 类型不匹配错误
    'type_not_match_error': [{
            'actual_key': 'root.data.0.type_id',
            'actual_vaule': '249',
            'expect_type': 'int'
        }
    ],
    # 数组长度不匹配错误
    'list_len_not_match_error': [{
            'actual_key': 'root.list',
            'actual_len': 1,
            'min_len': 2
        }
    ],
    # 枚举不匹配错误
    'enum_not_match_error': [{
            'actual_key': 'root.type',
            'actual_value': 12,
            'expect_enum': [11, 22]
        }
    ]
}

'''
print(mPactVerify.verify_info)

2.json 契约使用

from pactverify.matchers import PactJsonVerify

# 定义json契约格式
expect_format = {
    '$Matcher': {
        'code': 0,  # code key存在,值相等,code==0
        'msg': 'success',  # msg key存在,值相等,msg=='success'
        # [{}]结构
        'data': {
            '$EachLike': {
                "type_id": 249,  # type_id key存在,值类型相等,type(type_id) == type(249)
                "name": "王者荣耀",  # name key存在,值类型相等,type(name) == type("王者荣耀")
            }},
        'type': {
            '$Enum': [11, 22]
        },
        'list': {
            '$EachLike': {
                # $values,$params形式传递额外参数
                '$values': 11,
                '$params': {
                    'minimum': 2
                }
            }
        }
    }
}

# 实际返回数据
actual_data = {
    "msg": "success",
    "code": 1,
    'type': 12,
    "data": [{
        # type_id类型不匹配
        "type_id": '249',
        "name": "王者荣耀"
    }, {
        # 缺少name
        "type_id": 250,
    }, {
        # 比契约定义多index字段
        "type_id": 251,
        "name": "刺激战场",
        "index": 111
    }
    ],
    'list': [11]
}
# hard_mode默认为true,hard_mode = True时,实际返回key必须严格等于预期key;hard_mode = False时,实际返回key包含预期key即可
# separator可自定义指定json关键字标识符,默认为$
mPactJsonVerify = PactJsonVerify(expect_format, hard_mode=True, separator='$')
# 校验实际返回数据
mPactJsonVerify.verify(actual_data)
# 校验结果  False
print(mPactJsonVerify.verify_result)
''' 校验错误信息
错误信息输出actual_key路径:root.data.0.name形式
root为根目录,dict类型拼接key,list类型拼接数组下标(从0开始)
{   
    # 实际key少于预期key错误
    'key_less_than_expect_error': ['root.data.1.name'],
    # 实际key多与预期key错误,只在hard_mode = True时才报该错误
    'key_more_than_expect_error': ['root.data.2.index'],
    # 值不匹配错误
    'value_not_match_error': [{
            'actual_key': 'root.code',
            'actual_value': 1,
            'expect_value': 0
        }
    ],
    # 类型不匹配错误
    'type_not_match_error': [{
            'actual_key': 'root.data.0.type_id',
            'actual_vaule': '249',
            'expect_type': 'int'
        }
    ],
    # 数组长度不匹配错误
    'list_len_not_match_error': [{
            'actual_key': 'root.list',
            'actual_len': 1,
            'min_len': 2
        }
    ],
    # 元祖不匹配错误
    'enum_not_match_error': [{
            'actual_key': 'root.type',
            'actual_value': 12,
            'expect_enum': [11, 22]
        }
    ]
}
'''
print(mPactJsonVerify.verify_info)

3.python 类契约转 json 契约

1、python类契约不带参数
# python类契约
expect_format = Like({'k1': 'v1'})
# json契约
expect_format_json = {
    '$Like': {'k1': 'v1'}
}

2、python类契约带参数
# python类契约
expect_format = Like({'k1': 'v1'}, nullable=True)
# json契约
expect_format_json = {
    '$Like
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值