Python-httprunner接口契约校验

  • q2_677927
    了解作者
  • 17.7KB
    文件大小
  • zip
    文件格式
  • 0
    收藏次数
  • VIP专享
    资源类型
  • 0
    下载次数
  • 2022-04-29 06:33
    上传日期
公司前端吐槽后台接口有时会更改返回的数据结构,返回的字段名与字段类型与接口文档不一致,希望有一个快速检测接口返回数据的所有字段名与字段类型的方法
Python-httprunner接口契约校验.zip
  • PactVerify_demo-master
  • pactverify
  • tests.py
    53.5KB
  • matchers.py
    24.8KB
  • __init__.py
    107B
  • api_server.py
    1.9KB
  • pactverify_demo.py
    3.7KB
  • __init__.py
    0B
  • README.md
    10.5KB
  • test_pact.py
    2.2KB
  • .gitignore
    41B
内容介绍
# 接口断言引入契约校验 ## 一.背景 公司前端吐槽后台接口有时会更改返回的数据结构,返回的字段名与字段类型与接口文档不一致,希望有一个快速检测接口返回数据的所有字段名与字段类型的方法 以下方数据为例,要校验data数组中dict结构中的字段名与字段类型,可以写脚本遍历数据,但是由于每个接口返回的数据结构可能不一致,可能需要针对每个接口做不同的逻辑,所以需要一个比较通用的校验方法 ```python { "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": "刺激战场" } ] } ``` 在研究了[契约测试](https://www.pact.net.cn/documentation/what_is_pact.html)后,抽取[pact-python](https://github.com/pact-foundation/pact-python)部分代码,实现:自定义接口返回数据格式(【契约定义】)-实际响应数据格式校验(【契约校验】)的功能 备注:这里的【契约】等同于接口响应数据结构 ------------- ## 二.校验原则 >1.实际返回数据必须包含契约中定义的字段,可以多字段,但不能少 >2.字段值可以值相等或类型相等 目标:对返回数据进行全量(字段名-值/类型)校验 ------------- ## 三.基本使用 ### 安装: ```python pip install pactverify ``` ### 示例: ```python from pactverify.matchers import Matcher, Like, EachLike, 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("王者荣耀") }) }) # 实际返回数据 actual_data = { "msg": "success", "code": 0, "data": [{ # type_id类型不匹配 "type_id": '249', "name": "王者荣耀" }, { # 缺少name "type_id": 250, }, { # 比契约定义多index字段,通过校验 "type_id": 251, "name": "刺激战场", "index": 111 } ] } mPactVerify = PactVerify(expect_format) # 校验实际返回数据 mPactVerify.verify(actual_data) # 校验结果 False print(mPactVerify.verify_result) ''' 校验错误信息 错误信息输出actual_key路径:root.data.0.name形式 root为根目录,dict类型拼接key,list类型拼接数组下标(从0开始) { # dict类型key不匹配错误 'key_not_macth_error': ['root.data.1.name'], # 值不匹配错误 'value_not_match_error': [], # 类型不匹配错误 'type_not_match_error': [{ 'actual_key': 'root.data.0.type_id', 'actual_vaule': '249', 'expect_type': 'int' } ], # 数组长度不匹配错误 'list_len_not_match_error': [], # 元祖不匹配错误 'enum_not_match_error': [] } ''' print(mPactVerify.verify_info) ``` ### 1. Matcher类 #### 校验规则:值匹配 ```python # 预期11 expect_format_1 = Matcher(11) # 预期1.0 expect_format_2 = Matcher(1.0) # 预期'11' expect_format_3 = Matcher('11') # 预期返回数据actual为dict结构,actual['k1'] == 'v1' expect_format_4 = Matcher({'k1':'v1'}) ``` ### 2. Like类 #### 校验规则:类型匹配 ```python # 预期type(11) expect_format_1 = Like(11) # 预期type(1.0) expect_format_2 = Like(1.0) # 预期type('11') expect_format_3 = Like('11') # 预期返回数据actual为dict结构,actual['k1'] == type('v1') expect_format_4 = Like({'k1':'v1'}) ``` ### 3. EachLike类 #### 校验规则:数组类型匹配 ```python # 预期[type(11)] expect_format_1 = EachLike(11) # 预期[type(1.0)] expect_format_2 = EachLike(1.0) # 预期[type('11')] expect_format_3 = EachLike('11') # 预期[Like{'k1':'v1'}] expect_format_4 = EachLike({'k1': 'v1'}) # 预期[Like{'k1':'v1'}]或[],minimum为数组最小长度,默认minimum=1 expect_format_4 = EachLike({'k1': 'v1'}, minimum=0) ``` ### 4. Term类 #### 校验规则:正则匹配 ```python # 预期r'^\d{2}$',并且type(actual_data) == type(example),example也来测试正则表达式 expect_format_1 = Term(r'^\d{2}$', example=111) ``` ### 5. Enum类 #### 校验规则:枚举匹配 ```python # 预期11或22 expected_format_1 = Enum([11, 22]) # iterate_list为true时,当目标数据为数组时,会遍历数组中每个元素是否in [11, 22] expected_format_2 = Enum([11, 22],iterate_list=True) ``` ------------- ## 四.复杂规则匹配 ### 4.1 {{}}格式 ```python actual_data = { 'code': 0, 'msg': 'success', 'data': { "id": 1, "name": 'lili' } } expect_format = Like({ 'code': 0, 'msg': 'success', 'data': Like({ "id": 1, "name": 'lili' }) }) ``` ### 4.2 [[]]格式 ```python actual_data = [[{ "id": 1, "name": 'lili' }]] expect_format = EachLike(EachLike({ "id": 1, "name": 'lili' })) ``` ### 4.3 {[]}格式 ```python actual_data = { 'code': 0, 'msg': 'success', 'data': [{ "id": 1, "name": 'lili' },{ "id": 2, "name": 'lilei' }] } expect_format = Like({ 'code': 0, 'msg': 'success', 'data': EachLike({ "id": 1, "name": 'lili' }) }) ``` ### 4.4 Like-Term嵌套 ```python expect_format = Like({ 'code': 0, 'msg': 'success', 'data': Like({ "id": 1, "name": Term(r'\w*',example='lili') }) }) ``` ### 4.5 Like-Matcher嵌套 ```python expect_format = Like({ # name字段值类型匹配 'name': 'lilei', # age字段值匹配 'age': Matcher(12), }) ``` #### 说明: >1. Matcher,Like和EachLike类可以不限层级嵌套,Term和Enum则不能嵌套其他规则 >2. 匹配规则多层嵌套时,内层规则优先生效 ------------- ## 五.异常场景匹配 ### 5.1 null匹配 ```python # nullable为true时允许返回null,预期null和(actual为dict结构,actual['k1'] == 'v1' or null)形式 expect_format = Matcher({'k1': 'v1'},nullable=True) # nullable为true时允许返回null,预期null和(actual为dict结构,actual['k1'] == type('v1') or null)形式 expect_format = Like({'k1': 'v1'},nullable=True) # nullable为true时允许返回null,预期null和[null,{'k1':null}]形式 expect_format = EachLike({'k1': 'v1'},nullable=True) # nullable为true时允许返回null,预期null和11形式 expect_format = Term(r'^\d{2}$', example=11, nullable=True) # nullable为true时允许返回null,预期null和11/22/33形式 expect_format = Enum([11, 22, 33], nullable=True) ``` ### 5.2 {}匹配 ```python # dict_emptiable为true时,允许返回{},预期{}和(actual为dict结构,actual['k1'] == 'v1')形式 expect_format = Matcher({'k1': 'v1'},dict_emptiable=True) # dict_emptiable为true时,允许返回{},预期{}和(actual为dict结构,actual['k1'] == type('v1'))形式 expect_format = Like({'k1': 'v1'},dict_emptiable=True) ``` ### 5.3 json格式字符串匹配 ```python # actual为"{\"k1\":\"v1\"}"json字符串格式时,先进行json.dumps再校验 expect_format = Matcher({'k1':'v1'},jsonloads = True) # actual为"{\"k1\":\"v1\"}"json字符串格式时,先进行json.dumps再校验 expect_format = Like({'k1': 'v1'},jsonloads = True) # actual为"[{\"k1\":\"v1\"}]"json字符串格式时,先进行json.dumps再校验 expect_format = EachLike({'k1': 'v1'}, jsonloads = True) # actual为"[11,22]"json字符串格式时,先进行json.dumps再校验 expected_format = Enum([11, 22],jsonloads = True) ``` ### 5.4 key不存在匹配
评论
    相关推荐