自动化测试之httprunner框架hook函数实操

news2025/6/7 23:37:51

本篇介绍httprunner中hook函数的使用,以及通过编程能力实现建设自动化测试更全面的场景覆盖


前置:

互联网时代让我们更快的学习到什么是Httprunner

正文:

        经过上文了解到这个框架怎么使用之后,我们开始来探讨一下我们为什么要用hook函数?用hook函数能帮我们实现什么?能给我们带来什么收益?

举个例子:假设我们的业务系统目前是通过Kafka来实现消息的交互,A系统生产的消息B系统需要去消费处理后在生产消息给到下游系统

那么如果说我们需要为B系统编写这类流程的自动化,我们需要怎么实现呢?

一)设计

首先考虑一个问题:如果A系统是独立系统,如果我们写的自动化要依赖A系统的数据那就耦合度太高了。如果我们只考虑B系统的完整性,那么我们完全可以把A mock掉,将A生产的报文消息当作cases,通过python脚本来实现。

然后B系统消费后会操作数据库,那么我们断言是否可以也读数据库去判断是否预期

其次B会发消息来通知下游系统消费,那么我们是不是也可以写一个kafka监听消费消息,判断报文是否符合预期

二)实现

1、先写一个发送消息的函数,这个地方加一个参数是为了写多个cases

import json
from kafka import KafkaProducer

def sengMessage(tag):
    producer = KafkaProducer(bootstrap_servers='这个地方写集群名称')
    if('A' == tag):
        msg_dict = {
                "CMD": "这个地方是CMD",
                "Data": "这个地方是消息体",
                "Key": "这个是Key",
                "LogID": "681533193628954414",
                "Tag": "这个是标识",
                "TimeStamp": "这是个时间",
                "Topic": "这是个要发送的主题"
            }
        msg = json.dumps(msg_dict).encode()
        #partition这个地方写的是0表示放0这个Partition上了,如果要随机就看你有几个Partition,random一下
        producer.send("这个地方放主题topic", msg, partition=0)
    producer.close()

2、然后将这个函数放到debugtalk.py文件里面

3、编写一个cases,将此函数引用到setup_hooks

使用方式就是${函数名称(参数)},说明一下就是为啥要在setup_hooks里面使用,是因为需要在执行cases之前将消息发送之后系统消费到了才能走后面的流程(就是前置)

然后这个前置操作可以做:消息的发送、数据的处理(比如删除数据,更新数据等等)

4、编写一个操作数据库的函数

import pymysql
import yaml
from loguru import logger
from lib import utils


class MySQL(object):
    """Mysql数据库操作
    """
    db = {}

    def __init__(self, db):
        """初始化数据库对象
        Args:
            db (str): 数据库名字,代表了db配置的某个文件,数据库连接信息也在对应文件配置
        """
        file = f"{utils.get_root_path()}/conf/{db}.yml"

        with open(file, encoding="utf-8") as conf:
            self.db = yaml.load(conf, Loader=yaml.FullLoader)

    def execute(self, sql):
        """在mysql上执行一个sql语句,返回的结果为多条记录的元组,每条记录为dict,内容为字段-值字典
        Returns:
            [tuple]: 执行结果
        """
        self.db['cursorclass'] = pymysql.cursors.DictCursor

        try:
            connection = pymysql.connect(**self.db)
            logger.info(f"execute sql: [{sql}]")
            with connection.cursor() as cursor:
                cursor.execute(sql)
                data = cursor.fetchall()
                logger.debug(f"execute ret: [{data}]")
                connection.commit()
        finally:
            connection.close()
        return data
#怎么使用呢,就是直接用这个函数传配置文件名称,sql
if __name__ == '__main__':
    MySQL("auto").execute("select * from A limit 1")

设置放置存储数据库配置文件的目录

数据库配置

host: IP
port: 端口
user: 用户名
passwd: 密码
db: 数据库

5、能操作数据库之后,那么我们是否可以将查询回来的全部重要字段(什么自增主键ID、时间啥的就不用断言了)进行判断了,写一个比较json的函数

class Check(object):

    def CheckSql(prama):
        db = 'auto'
        errmsgl_success = 'success'
        sql = 'SELECT A,B,C,D,E,F,G,H,I,J,K from AAA where aa=' + '\'' + str(
            prama) + '\''
        sql_count = 'SELECT count(1) from AAA  WHERE (aa = ' + "\'" + str(
            prama) + "\'" + ')'
        # 先查询条数,没有就重试,如果重试还没有就失败
        count = MySQL(db).execute(sql_count)[0]['count(1)']
        retry = 0
        while count == 0 and retry < 15:
            time.sleep(3)
            retry = retry + 1
            count = MySQL(db).execute(sql_count)[0]['count(1)']

        aa = MySQL(db).execute(sql)[0]

        response = json.dumps(aa)
        print(response)
        # 这个地方,假如A字段是一个JSON,这个地方是做了一个处理,让这个json排序,就不会出现每次查询这个json都是乱序得导致断言失败
        # 假设A字段:[{fee:1},{fee:2},{fee:3}],那么我们就用fee来排序
        A = eval(str(aa["A"]))
        aa["A"] = sorted(A, key=lambda x: (x['fee']), reverse=True)
        print(json.dumps(aa))
        # 这个地方用的直接是传进来得参数作为文件名称
        checkfile__detail = str(prama) 
        detail_ret = Check.checkfile_json(aa, checkfile__detail)
        if detail_ret != errmsgl_success:
            return '文件名称:' + checkfile__detail + ', 失败原因: ' + detail_ret

        return errmsgl_success
    
    # 读取对应的预期文件,这个函数可以抽出来,当一个公共方法
    def checkfile_json(requestdata, checkfile):
        # 文件地址当前项目/checkfile/checkfile.json
        basic_url = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/checkfile'
        if checkfile:
            with open(basic_url + checkfile + '.json', 'r') as f:
                setdatas = json.load(f)

        return Check.cmp(requestdata, setdatas)

    def cmp(src_data, dst_data):
        msg = 'success'

        if isinstance(dst_data, dict):
            """若为dict格式"""
            for key in dst_data:
                if key not in src_data:
                    return 'key: ' + str(key) + ' 在请求中不存在'
              
                msg = Check.cmp(src_data[key], dst_data[key])
                if msg != 'success':
                    return msg
        elif isinstance(dst_data, list):
            """若为list格式"""
            for src_list, dst_list in zip((src_data), (dst_data)):
                """递归"""
                msg = Check.cmp(src_list, dst_list)
                if msg != 'success':
                    return msg
        else:
            if str(src_data) != str(dst_data):
                return 'src_data != dst_data, src_data: ' + str(src_data) + ', dst_data: ' + str(dst_data)
        return msg

6、断言函数既然已经写好了,那就直接引用,同上面那个流程,加载到debugtaik.py文件之后,我们需要在cases断言处加上此函数,还是用${函数名称(参数)}来引用

7、最后编写一下消费kafka消息进行断言的函数

    def check_kafka_messgae(topic, bootstrap_servers, checkfile, enable_auto_commit=False, consumer_timeout_ms=300):
        # 参数分别是主题,集群,断言文件地址,自动提交,超时时间
        consumer = KafkaConsumer(bootstrap_servers=[bootstrap_servers], enable_auto_commit=enable_auto_commit,
                                 consumer_timeout_ms=consumer_timeout_ms)
        # 这个地方只监听一个partition == 0的
        topic_partition = TopicPartition(topic=topic, partition=0)
        lastoffset = consumer.end_offsets([topic_partition])[topic_partition]
        consumer.assign([topic_partition])
        consumer.seek(topic_partition, lastoffset - 1)
        messagelist = ''
        for message in consumer:
            messagelist = message.value
        messagelist = json.loads(json.loads(str(messagelist, 'utf-8'))['Data'])
        print('topic数据' + str(messagelist))
        # checkfile_json这个方法上面写得函数里面有,直接调用
        return checkfile_json(messagelist, checkfile)

8、同上,还是将这个函数加入到debugtaik.py,在validate里面进行断言判断

总结:

将上面的流程串起来之后发现,从kafak消息的发送、数据库的查询、文件读取/数据判断,到kafka消息监听断言整个流程能够完成上述的诉求。

通过一个例子来解读hook函数的作用。在真实的业务场景下,我们在编写自动化cases的时候完全可以用纯代码的方式来实现我的复杂的业务场景。通过这种方式能更有效的认可自动化去替代人工操作。


后话:

个人认为自动化的灵魂不是用什么工具,而是断言。不管是人工还是程序自动操作都需要有一个判断依据,如果这个判断依据十分有效,那么我们只需要完善场景cases就能实现自动化替换人工(百分之80吧)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1592751.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SecureCRT通过USB-Servial ch340串口无法连接单片机

通过USB To TTL连线 STM32F103-PRO&#xff0c;烧制程序到单片机上&#xff0c;通过SecureCRT通过USB-Servial ch340串口无法链接RS232升USB转TTL连接正确 开发板连接正确 问题&#xff1a;SecureCRT串口连接没有反应 问题分析&#xff1a;1、检查ch340串口驱动 查看设备管…

海洋信息管理系统:守护蓝色星球,促进海洋经济新发展

海洋&#xff0c;覆盖地球表面超过七成的广阔水域&#xff0c;是生命之源&#xff0c;也是经济发展的重要空间。然而&#xff0c;随着人类活动的增加&#xff0c;海洋生态环境面临严峻挑战&#xff0c;海洋资源的可持续利用成为全球关注的焦点。在这样的背景下&#xff0c;构建…

openssl 如何从pfx格式证书 获取证书序列号信息

已知&#xff1a;一个个人证书文件 test.pfx 求&#xff1a;如何通过openssl查看其对应证书的序列号信息&#xff1f; 踩坑之&#xff1a;unable to load certificate! openssl x509 -in xxx.cert -noout -serial 命令可查看证书序列号&#xff0c;但是这个-in 的输入必须是私…

一步一步学习使用 MediaSource 实现动态媒体流

学习前的参考 为什么视频网站的视频链接地址是blob&#xff1f; - 掘金 MediaSource - Web API 接口参考 | MDN 在示例中前往下载源代码&#xff1a; netfix/demo/bufferWhenNeeded.html at gh-pages nickdesaulniers/netfix GitHub 下载 demo 目录&#xff0c;对 bufferW…

量子信息产业生态研究(一):关于《量子技术公司营销指南(2023)》的讨论

写在前面。量子行业媒体量子内参&#xff08;Quantum Insider&#xff09;编制的《量子技术公司营销指南》是一本实用的英文手册&#xff0c;它旨在帮助量子科技公司建立有效的营销策略&#xff0c;同时了解如何将自己定位成各自的行业专家。本文对这篇指南的主要内容进行了翻译…

C语言中的编译和链接

系列文章目录 文章目录 ​编辑 系列文章目录 文章目录 前言 一、 翻译环境和运行环境 二、 翻译环境 2.1 编译 2.1.1 预处理 2.1.2 编译 2.1.2.1 词法分析 : 2.1.2.2 语法分析 2.1.2.3 语义分析 2.1.3 汇编 2.2 链接 三、运行环境 前言 在我们平常的写代码时&#xff0c;我们很…

set 类 和 map 类

1. 关联式容器 关联式容器也是用来存储数据的&#xff0c;与序列式容器不同的是&#xff0c;其里面存储的是<key, value>结构的 键值对&#xff0c;在数据检索时比序列式容器效率更高 2. 键值对 用来表示具有一一对应关系的一种结构&#xff0c;该结构中一般只包含…

你的系统是如何跟MySQL打交道的

1、Java 工程师眼中的数据库是什么东西? 从今天开始&#xff0c;我们将要开始一个MySQL的专栏&#xff0c;一起来研究MySQL数据库的底层原理和各种实践案例&#xff0c;以及互联网公司的技术方案。 现在我们先来看看&#xff0c;在一个Java工程师眼中的数据库是什么东西? 平时…

开源 Ruo-Yi 项目引入 Mybatis-Plus:3.5.3 报错ClassNotFoundException:

开源 Ruo-Yi 项目引入 Mybatis-Plus:3.5.3 报错ClassNotFoundException&#xff1a; Caused by: java.lang.ClassNotFoundException: com.baomidou.mybatisplus.extension.plugins.MybatisPlusInter1 分析问题 控制台报错说明我们引入的 mybatis-plus 的依赖里找不到com.baom…

怎么恢复删除的回收站数据?分享多种恢复方法

在日常使用电脑的过程中&#xff0c;回收站是我们经常打交道的一个功能。它帮助我们管理不再需要的文件&#xff0c;但有时候&#xff0c;我们可能会不小心删除了重要文件&#xff0c;或者误清空了回收站。那么&#xff0c;面对这种情况&#xff0c;我们该如何恢复删除的回收站…

小程序面试题之性能优化提高10道

1.你使用过哪些方法&#xff0c;来提高微信小程序的应用速度&#xff1f; 提高页面加载速度 用户行为预测 减少默认data的大小 组件化方案 控制包的大小 压缩代码&#xff0c;清理无用代码 采用分包策略 启用本地缓存 参考地址&#xff1a;https://blog.csdn.net/wu_xianqiang/…

Linux上的可执行文件在Windows上是不能运行的

一、概要 1、可执行文件的格式 Linux上的可执行文件是elf格式的 Windows上的可执行文件是exe格式的 Linux上的可执行文件在Windows上是不能运行的 2、程序的普通构建与静态构建 普通构建&#xff1a; 一个.c文件&#xff0c;用gcc命令编译成可执行文件(程序)&#xff0c…

数据结构排序篇上

排序的概念及其运用 排序的概念 排序 &#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性 &#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&…

分类预测 | Matlab实现基于迁移学习和GASF-CNN-Mutilhead-Attention格拉姆角场和卷积网络多头注意力机制多特征分类预测/故障识别

分类预测 | Matlab实现基于迁移学习和GASF-CNN-Mutilhead-Attention格拉姆角场和卷积网络多头注意力机制多特征分类预测/故障识别 目录 分类预测 | Matlab实现基于迁移学习和GASF-CNN-Mutilhead-Attention格拉姆角场和卷积网络多头注意力机制多特征分类预测/故障识别分类效果基…

动态规划原理及其在优化问题中的应用解析

动态规划原理及其在优化问题中的应用解析 一、最优子结构二、重叠子问题三、何时使用动态规划法四、伪代码示例五、C代码示例七、详细说明动态规划原理7.1、最优子结构7.2 重叠子问题7.3 动态规划的实现 八、结论 动态规划是一种解决优化问题的方法&#xff0c;它通过将原问题分…

神经网络--反向传播算法推导

神经网络–反向传播算法推导 文章目录 神经网络--反向传播算法推导概述神经网络模型反向传导算法 概述 以监督学习为例&#xff0c;假设我们有训练样本集 ( x ( i ) , y ( i ) ) (x^{(i)},y^{(i)}) (x(i),y(i))&#xff0c;那么神经网络算法能提供一种复杂且非线性的假设模型 …

滚雪球学Java(75):Java零基础,轻松学会文件读写技巧

咦咦咦&#xff0c;各位小可爱&#xff0c;我是你们的好伙伴——bug菌&#xff0c;今天又来给大家普及Java SE相关知识点了&#xff0c;别躲起来啊&#xff0c;听我讲干货还不快点赞&#xff0c;赞多了我就有动力讲得更嗨啦&#xff01;所以呀&#xff0c;养成先点赞后阅读的好…

mp3怎样才能转换成wav格式?音频互相转换的方法

一&#xff0c;什么是WAV WAV&#xff0c;全称为波形音频文件&#xff08;Waveform Audio File Format&#xff09;&#xff0c;是一种由微软公司和IBM公司联合开发的音频文件格式。自1991年问世以来&#xff0c;WAV格式因其无损的音频质量和广泛的兼容性&#xff0c;成为了多…

【Godot4.2】CanvasItem绘图函数全解析 - 7.自定义节点TextBoard

概述 之前发布的几篇文章几乎阐述了CanvasItem绘图函数最基础的内容。 本篇结合draw_style_box()和TextParagraph类&#xff0c;自定义了一个可以自适应宽高显示多行文本&#xff0c;且带有一个样式盒作为背景的文字板节点TextBoard。 系列目录 0.概述1.绘制简单图形2.设定绘…

kali工具----域名IP及路由跟踪

域名IP及路由跟踪 测试网络范围内的IP地址或域名也是渗透测试的一个重要部分。通过测试网络范围内的IP地址或域名&#xff0c;确定是否有人入侵自己的网络中并损害系统。不少单位选择仅对局部IP基础架构进行渗透测试&#xff0c;但从现在的安全形势来看&#xff0c;只有对整个I…