接口自动化-httprunner3引入基于契约校验响应数据

2023-11-18

背景

在进行接口自动化时,需要对返回数据进行校验。
在响应数据中字段少的时候,可以对每个字段进行校验。但当响应数据中字段多时,单独写校验比较麻烦。
引入基于契约的校验,可以对返回数据进行基于值或者类型的全量校验。

安装

pip install pactverify

python类契约

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

# 定义契约格式
expect_format = Matcher({
    'code': 0,  #  key存在,值相等,code==0
    'msg': 'success',  #  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]), #枚举类型,值为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)

引入Httprunner

pacts.py存放接口契约

项目根目录新增pacts.py文件,用来存放接口的Python类契约规则

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


class Pact:
    # /model/custom/type/query接口契约
     model_custom_type_query= Matcher(
        {
            "success": 1,#值匹配
            "code": 1001,#值匹配
            "msg":"请求成功",#值匹配
            "data": EachLike( {#数组匹配
            "createTime": 20230312115756,#类型匹配
            "modifyTime": 20230312115756,
            "code": 15,
            "modelId": "bee2ea6ec1a7439480995e80ae12b139",
            "modelType": "Placement"
        }),
            "requestId": Like("5a3664c2-f502-4ac0-8f38-b294b671e0a6")#类型匹配

        }
    )

debugtalk.py加入处理函数

def pactverify(response, pact_name):
    if not hasattr(Pact, pact_name):
        raise PactVerifyError('{}契约未找到'.format(pact_name))


    rsp_json = response.resp_obj.json()

    expect_format = getattr(Pact, pact_name)
    mPactVerify = PactVerify(expect_format)
    mPactVerify.verify(rsp_json)

    response.verify_result = mPactVerify.verify_result #将校验结果写入reponse
    response.verify_info = mPactVerify.verify_info
    if  response.verify_result==False:
        logger.info(f"契约校验失败{mPactVerify.verify_info}")

传入pact_name,即接口契约名称,如果Pact类中存在该契约,则将契约内容与response进行比对,并将结果写给reponse的verify_result,将校验信息写给response的verify_info

reponse.py源码修改

在pactverify方法里,将校验结果和信息写给了response,但是这两个字段在httprunner里没有定义。
所以需要在httprunner的response.py中加入定义
image.png

测试用例写法


config:
    name: 模型类型查询
    base_url: ${ENV(base_url)}

teststeps:
    - name: "模型类型查询"
      setup_hooks:
        - ${custom_reports(模型管理, 模型类型查询)} #根据id查询所属类型
      request:
        method: POST
        url: /model/custom/type/query
        headers:
            cookie: ${ENV(cookie)}
        json:
            ["bee2ea6ec1a7439480995e80ae12b139"]
      teardown_hooks:
        # teardown处理,将verify_result和verify_info写入response对象
        - ${pactverify($response,model_custom_type_query)}
      validate:
        -   eq: [ status_code, 200 ] # 检验响应状态码是否等于200
        -   eq: [ verify_result,True ]

在测试用例步骤中加入teardown_hooks,调用pactverify方法,传入该接口的契约名称进行校验。
在validate步骤中,checkitem写为verify_result,调用reponse中的verify_result字段,进行断言。
image.png
执行用例,查看打印,契约校验已经进行了判断。
契约校验结果为失败,原因是响应中比契约规则多了一个msg字段。

附录-匹配规则

Match类-值匹配

expect_format_1=Matcher(11) #预期结果为11

预期返回数据actual为dict结构,actual[‘k1’] == ‘v1’ python类契约格式

expect_format_4=Matcher({'k1':'v1'})

Like类-类型匹配

# 预期type(11) python类契约
 expect_format_1=Like(11)
# 预期返回数据actual为dict结构,actual['k1'] == type('v1') python类契约 
expect_format_4=Like({'k1':'v1'})

EachLike 类-数组匹配

# 预期[type(11)] python类契约 
expect_format_1=EachLike(11)
# 预期[Like{'k1':'v1'}]或[],minimum为数组最小长度,默认minimum=1 python类契约 
expect_format_5=EachLike({'k1':'v1'},minimum=0)


Term类-正则匹配

# 预期r'^\d{2}$',并且type(actual_data) == type(example),example也用来测试正则表达式  python类契约
expect_format_1 = Term(r'^\d{2}$', example=11)

# 预期r'^\d{2}$',example用来测试正则表达式,type_strict = False时跳过对example参数类型校验   python类契约
expect_format_2 = Term(r'^\d{2}$', example="11", type_strict=False)

Enum类-枚举匹配

# 预期11或22  python类契约
expected_format_1 = Enum([11, 22])


# iterate_list为true时,当目标数据为数组时,会遍历数组中每个元素是否in [11, 22]  python类契约
expected_format_2 = Enum([11, 22], iterate_list=True)

复杂规则匹配

1.{{}}格式

actual_data = {
    'code': 0,
    'msg': 'success',
    'data': {
        "id": 1,
        "name": 'lili'
    }
}

# python类契约
expect_format = Like({
    'code': 0,
    'msg': 'success',
    'data': Like({
        "id": 1,
        "name": 'lili'
    })
})

2.[[]] 格式

actual_data = [[{
    "id": 1,
    "name": 'lili'
}]]

# python类契约
expect_format = EachLike(EachLike({
    "id": 1,
    "name": 'lili'
}))

3.{[]}格式

actual_data = {
    'code': 0,
    'msg': 'success',
    'data': [{
        "id": 1,
        "name": 'lili'
    },{
        "id": 2,
        "name": 'lilei'
    }]
}

# python类契约
expect_format = Like({
    'code': 0,
    'msg': 'success',
    'data': EachLike({
        "id": 1,
        "name": 'lili'
    })
})


4.Like-Term 嵌套

actual_data = {
    'code': 0,
    'msg': 'success',
    'data': {
        "id": 1,
        "name": 'lili'
    }
}

# python类契约
expect_format = Like({
    'code': 0,
    'msg': 'success',
    'data': Like({
        "id": 1,
        "name": Term(r'\w*', example='lili')
    })
})

}

5.Like-Matcher 嵌套

actual_data = {
    'name': 'lilei',
    'age': 12
}

# python类契约
expect_format = Like({
    # name字段值类型匹配
    'name': 'lilei',
    # age字段值匹配
    'age': Matcher(12),
})

说明:

  1. Matcher,Like 和 EachLike 类可以不限层级嵌套,Term 和 Enum 则不能嵌套其他规则
  2. 匹配规则多层嵌套时,内层规则优先生效

异常场景匹配

1.null 匹配

# nullable为true时允许返回null,预期null和(actual为dict结构,actual['k1'] == 'v1' or null)形式   python类契约
expect_format = Matcher({'k1': 'v1'}, nullable=True)


# nullable为true时允许返回null,预期null和(actual为dict结构,actual['k1'] == type('v1') or null)形式   python类契约
expect_format = Like({'k1': 'v1'}, nullable=True)


# nullable为true时允许返回null,预期null和[null,{'k1':null}]形式   python类契约
expect_format = EachLike({'k1': 'v1'}, nullable=True)


# nullable为true时允许返回null,预期null和11形式   python类契约
expect_format = Term(r'^\d{2}$', example=11, nullable=True)

}

# nullable为true时允许返回null,预期null和11/22/33形式   python类契约
expect_format = Enum([11, 22, 33], nullable=True)
# nullable为true时允许返回null,预期null和11/22/33形式   json契约

备注:nullable 参数在 hard_mode = True 时也生效

2.{}匹配

# dict_emptiable为true时,允许返回{},预期{}和(actual为dict结构,actual['k1'] == 'v1')形式   python类契约
expect_format = Matcher({'k1': 'v1'}, dict_emptiable=True)

# dict_emptiable为true时,允许返回{},预期{}和(actual为dict结构,actual['k1'] == type('v1'))形式   python类契约
expect_format = Like({'k1': 'v1'}, dict_emptiable=True)

备注:dict_emptiable 在 hard_mode = True 时也生效

3.json 格式字符串匹配

# actual为"{\"k1\":\"v1\"}"json字符串格式时,先进行json.loads再校验   python类契约
expect_format = Matcher({'k1': 'v1'}, jsonloads=True)


# actual为"{\"k1\":\"v1\"}"json字符串格式时,先进行json.loads再校验   python类契约
expect_format = Like({'k1': 'v1'}, jsonloads=True)
# actual为"{\"k1\":\"v1\"}"json字符串格式时,先进行json.loads再校验   json契约


# actual为"[{\"k1\":\"v1\"}]"json字符串格式时,先进行json.loads再校验  python类契约
expect_format = EachLike({'k1': 'v1'}, jsonloads=True)
# actual为"[{\"k1\":\"v1\"}]"json字符串格式时,先进行json.loads再校验  json契约

# actual为"[11,22]"json字符串格式时,先进行json.loads再校验   python类契约
expected_format = Enum([11, 22], jsonloads=True)
# actual为"[11,22]"json字符串格式时,先进行json.loads再校验   json契约

}

4.key 不存在匹配

# key_missable为true时,允许key不存在,key存在时走正常校验;Matcher,Like,EachLike,Term和Enum类都可使用该属性   python类契约
expect_format = Matcher({
    'code': Like(0, key_missable=True),
    'msg': Matcher('success', key_missable=True),
    'data': EachLike(11, key_missable=True),
    'age': Term(r'^\d{2}$', example=11, key_missable=True),
    'num': Enum([11, 22, 33], key_missable=True)
})

      

# dict_key_missable为true时,允许dict结构中的key不存在,但key不能多(hard_mode=true时),key存在时正常校验  python类契约
expected_format = Matcher({
    'name': 'lilei',
    'age': 12,
    'sex': 'man'
}, dict_key_missable=True)


# dict_key_missable为true时,允许dict结构中的key不存在,但key不能多(hard_mode=true时),key存在时正常校验   python类契约
expected_format = Like({
    'name': 'lilei',
    'age': 12,
    'sex': 'man'
}, dict_key_missable=True)


# dict_key_missable为true时,允许dict结构中的key不存在,但key不能多(hard_mode=true时),key存在时正常校验   python类契约
expected_format = EachLike({
    'name': 'lilei',
    'age': 12,
    'sex': 'man'
}, dict_key_missable=True)
# dict_key_missable为true时,允许dict结构中的key不存在,但key不能多(hard_mode=true时),key存在时正常校验   json契约

5.多类型匹配

# actual数据为type(11)或type('11'),extra_types可以添加多个示例数据,对基础数据类型(int,float,boolean,str,None)示例有效,对list dict等类型无效  python类契约
expect_format = Like(11, extra_types=['11'])

# actual数据为[type(11)]或[type('11')],extra_types可以添加多个示例数据,对基础数据类型示例(int,float,boolean,str,None)有效,对list dict等类型无效  python类契约
expect_format = EachLike(11, extra_types=['11'])

6.非强制字段匹配

expect_format = Like({'k1': 'v1'})
# hard_mode=False只匹配契约中定义的字段,实际返回的多余字段忽略    python类契约
mPactVerify = PactVerify(expect_format, hard_mode=False)
actual_data = {'k1': 'v1', 'k2': 'v2'}
# 只校验k1字段,k2字段忽略
mPactVerify.verify(actual_data)


# hard_mode=False只匹配契约中定义的字段,实际返回的多余字段忽略   json契约
mPactJsonVerify = PactJsonVerify(expect_format, hard_mode=False)
actual_data = {'k1': 'v1', 'k2': 'v2'}
# 只校验k1字段,k2字段忽略
mPactJsonVerify.verify(actual_data)

备注:
1. key_missable 在 hard_mode = True 时也生效
2. key_missable 针对 actual_data 本身的 key,dict_key_missable 针对 actual_data 字典中的 key,可以同时生效
注意:异常匹配场景越多,代表接口数据格式越不规范

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

接口自动化-httprunner3引入基于契约校验响应数据 的相关文章

随机推荐

  • 华为OD机试真题-优秀学员统计 【2023.Q1】

    题目描述 公司某部门软件教导团正在组织新员工每日打卡学习活动 他们开展这项学习活动已经一个月了 所以想统计下这个月优秀的打卡员工 每个员工会对应一个id 每天的打卡记录记录当天打卡员工的id集合 一共30天 请你实现代码帮助统计出打卡次数t
  • 算法:双指针解决数组划分和数组分块问题

    文章目录 实现原理 实现思路 典型例题 移动0 复写0 快乐数 盛最多水的容器 有效三角形的个数 三数之和 四数之和 总结 在快速排序或者是其他和数组有关的题目中 有很经典的一类题目是关于数组划分的 数组划分就是把数组按照一定的规则划分为不
  • Androidmainfest主配置文件以及intent的跳转

  • openwrt利用arp获取局域网设备IP

    openwrt利用arp获取局域网设备IP 文章目录 openwrt利用arp获取局域网设备IP 1 前言 2 ARP概念 3 arp局域网搜索设备实现思路和代码 1 前言 目前我们通过arp协议搜索局域网设备 根据局域网设备地址判断子设备
  • centos linux部署pxe服务器实现自动装机,照做就行

    大家好 今天分享一下在centos linux上部署pxe服务器来实现自动化的装机 关于这个东西的话 记住一点就可以了 就是pxe可以给很多服务器自动的安装操作系统 这样省时省力 这是pxe服务器的工作流程 我个人觉得他已经很详细了 下面来
  • python--商店购物案例(字典篇)--小黑学习驿站

    目录 案例 def 函数说明 global 内部声明函数 案例 水果店老板有N种水果 如果老板要新进一批水果该怎么循环添加 当客人买不同水果的时候该怎样计算 思路 1 首先思路是水果老板店里的水果和价钱做一个字典 然后利用字典循环添加新的水
  • 使用jcvi绘制微共线性(Microsynteny)

    本文主要介绍如何使用JCVI的synteny子命令基于已有的共线性分析结果 展现局部的共线性 需要准备的三个输入文件 记录物种内或者物种间的共线性基因对 记录基因坐标的bed文件 布局文件 第一步 基于已有的共线性分析结果 WGDI MCs
  • VS登录问题 无法刷新账户凭证 (Microsoft Visual Studio)

    1 问题描述 VS登录时 弹出错误 无法刷新此账户的凭证 2 解决办法 打开默认的浏览器 我的电脑上默认浏览器是搜狗 1 打开选项设置 2 打开Internet选项 点击连接 再点击局域网设置 3 勾选自动检测设置 取消其它勾选 4 VS恢
  • MySQL之DCL

    DCL Data Control Language DDL create alter drop DML insert update delete DQL select show DCL grant revoke 我们现在默认使用的都是 ro
  • 把多张 PNG 图片拼在一起合成一张 RAW 格式的图片(附代码)

    把多张 PNG 图片拼在一起合成一张 RAW 格式的图片 设定好输入和输出的路径即可 代码如下 import numpy import os import argparse from PIL import Image 把多张 PNG 图片拼
  • 【计算机毕业设计】鲜花销售系统

    鲜花销售系统设计与实现 现代经济快节奏发展以及不断完善升级的信息化技术 让传统数据信息的管理升级为软件存储 归纳 集中处理数据信息的管理方式 本鲜花销售系统就是在这样的大环境下诞生 其可以帮助管理者在短时间内处理完毕庞大的数据信息 使用这种
  • Tomcat——IDEA & Eclipse部署Web项目

    目录 IDEA部署Web项目 IDEA配置Tomcat 部署web项目 IDEA与tomcat的相关配置 Eclipse部署Web项目 Eclipse配置Tomcat 部署web项目 IDEA部署Web项目 跳转到目录 一 IDEA配置To
  • 性能测试连载 (5)-jmeter 下的性能指标监听

    咨询微信 uhz2008 性能指标监听 概述 性能测试过程中 想要得到比较靠谱的性能数据 就不得不对各种性能数据进行动态监听 jmeter中提供了很多性能数据的监听器 我们通过监听器可以来分析性能瓶颈 本文用吞吐量模式 演示200线程的负载
  • 抖音/快手自动播放下一个视频,每天领红包,程序员躺平了一样赚钱

    你跑的慢 周围到处都是笑声 你跑的快 周围到处都是风声 每个优秀的人都有一段沉默的时光 我们把它叫做扎根 前言 哈喽 大家好 我是一条 最近热榜真是越来越卷 都是万字起步 还不一定榜一 一条今天也是拼了 为了能上榜一 写点压箱底的东西 先问
  • 看红帽巨佬解析⭐《一、G1垃圾回收期简介》⭐

    笔者最近在看关于G1垃圾收集器 发现了一篇十分优秀的文章 来自红帽 Red Hat 大佬 笔者通过自己的理解后翻译后 有了本篇文章 本篇是Part 1 原文地址 序 对于大多数人来说 Java垃圾收集器是一个黑匣子 可以愉快地开展业务 程序
  • PLSQL Developer 下载、安装及汉化详细教程(全网最详细且附有下载链接,保姆级教学,本人已操作确保有效)

    PLSQL Developer 12 0 7 64 bit 下载 安装及汉化教程 全网最详细且附有下载链接 保姆级教学 本人已操作确保有效 一 下载 下载地址 https www allroundautomations com regist
  • 数学建模系列-优化模型---(四)神经网络模型

    神经网络在优化中的应用 万能的模型 误差修正函数 每次根据训练得到的结果与预想结果进行误差分析 进而修改权值和阈值 一步一步得到能输出和预想结果一致的模型 举一个例子 比如某厂商生产一种产品 投放到市场之后得到了消费者的反馈 根据消费者的反
  • 2022 弱口令安全实验室招新赛-靶机挑战记录

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 ubuntu 代码执行getshell 获取webshell 二 server 2008r2 EW 流量代理 ms17010 三 AD机器账号伪造漏洞 域
  • 期货公司数字化转型,这三个方面值得注意

    在以 私域运营 期货行业新增长引擎 为主题的金仕达2022 期货互联网转型私享会上 长江期货互金中心总经理刘吴伟围绕 网金部的定位和演变 当前期货行业数字化运营的痛点和难点 数字金融业务的实践趋势 三方面进行了关于 期货行业的数字化运营痛点
  • 接口自动化-httprunner3引入基于契约校验响应数据

    背景 在进行接口自动化时 需要对返回数据进行校验 在响应数据中字段少的时候 可以对每个字段进行校验 但当响应数据中字段多时 单独写校验比较麻烦 引入基于契约的校验 可以对返回数据进行基于值或者类型的全量校验 安装 pip install p