pytest系列——pytest_runtest_makereport钩子函数获取测试用例执行结果
前言
pytest测试框架提供的很多钩子函数方便我们对测试框架进行二次开发,可以根据自己的需求进行改造。
例如:钩子方法:pytest_runtest_makereport ,可以更清晰的了解测试用例的执行过程,并获取到每个测试用例的执行结果。
pytest_runtest_makereport方法简介
先看下相关的源码,在 _pytest/runner.py 文件下,可以导入之后查看:

源码:
from _pytest import runner# 对应源码def pytest_runtest_makereport(item, call):""" return a :py:class:`_pytest.runner.TestReport` objectfor the given :py:class:`pytest.Item` and:py:class:`_pytest.runner.CallInfo`."""
装饰器 pytest.hookimpl(hookwrapper=True, tryfirst=True) 解释:
@pytest.hookimpl(hookwrapper=True)装饰的钩子函数,有以下两个作用:
1、可以获取到测试用例不同执行阶段的结果(setup,call,teardown)
2、可以获取钩子方法 pytest_runtest_makereport(item, call) 的调用结果(yield返回一个测试用例执行后的result对象)和调用结果result对象中的测试报告(返回一个report对象)
pytest_runtest_makereport(item, call) 钩子函数参数解释:
1、 item 是测试用例对象;
2、 call 是测试用例的测试步骤;具体执行过程如下:
①先执行 when="setup" ,返回setup用例前置操作函数的执行结果。
②然后执行 when="call" ,返回call测试用例的执行结果。
③最后执行 when="teardown" ,返回teardown用例后置操作函数的执行结果。
第一个案例
conftest.py 文件编写 pytest_runtest_makereport 钩子方法,打印运行过程和运行结果。
# conftest.pyimport pytest@pytest.hookimpl(hookwrapper=True, tryfirst=True)def pytest_runtest_makereport(item, call):print('------------------------------------')# 获取钩子方法的调用结果,返回一个result对象out = yieldprint('用例执行结果', out)# 从钩子方法的调用结果中获取测试报告report = out.get_result()print('测试报告:%s' % report)print('步骤:%s' % report.when)print('nodeid:%s' % report.nodeid)print('description:%s' % str(item.function.__doc__))print(('运行结果: %s' % report.outcome))
test_a.py 写一个简单的用例:
def test_a():'''用例描述:test_a'''print("123")
运行结果:


结果分析:
从结果可以看到,测试用例的执行过程会经历3个阶段:
setup -> call -> teardown
每个阶段会返回 Result 对象和 TestReport 对象,以及对象属性。(setup和teardown上面的用例默认没有,结果都是passed。)
第二个案例
给用例写个 fixture() 函数增加测试用例的前置和后置操作; conftest.py 如下:
import pytest@pytest.hookimpl(hookwrapper=True, tryfirst=True)def pytest_runtest_makereport(item, call):print('------------------------------------')# 获取钩子方法的调用结果out = yieldprint('用例执行结果', out)# 从钩子方法的调用结果中获取测试报告report = out.get_result()print('测试报告:%s' % report)print('步骤:%s' % report.when)print('nodeid:%s' % report.nodeid)print('description:%s' % str(item.function.__doc__))print(('运行结果: %s' % report.outcome))@pytest.fixture(scope="session", autouse=True)def fix_a():print("setup 前置操作")yieldprint("teardown 后置操作")
运行结果:


第三个案例
fixture() 函数的 setup 前置函数在执行时异常,即 setup 执行结果为 failed ,则后面的 call 测试用例与 teardown 后置操作函数都不会执行。
此时的状态是 error ,也就是代表测试用例还没开始执行就已经异常了。(在执行前置操作函数的时候就已经发生异常)
import pytest@pytest.hookimpl(hookwrapper=True, tryfirst=True)def pytest_runtest_makereport(item, call):print('------------------------------------')# 获取钩子方法的调用结果out = yieldprint('用例执行结果', out)# 从钩子方法的调用结果中获取测试报告report = out.get_result()print('测试报告:%s' % report)print('步骤:%s' % report.when)print('nodeid:%s' % report.nodeid)print('description:%s' % str(item.function.__doc__))print(('运行结果: %s' % report.outcome))@pytest.fixture(scope="session", autouse=True)def fix_a():print("setup 前置操作")assert 1 == 2yieldprint("teardown 后置操作")
运行结果:


第四个案例
setup 前置操作函数正常执行,测试用例 call 执行发生异常。
此时的测试用例执行结果为 failed
# conftest.pyimport pytest@pytest.hookimpl(hookwrapper=True, tryfirst=True)def pytest_runtest_makereport(item, call):print('------------------------------------')# 获取钩子方法的调用结果out = yieldprint('用例执行结果', out)# 3. 从钩子方法的调用结果中获取测试报告report = out.get_result()print('测试报告:%s' % report)print('步骤:%s' % report.when)print('nodeid:%s' % report.nodeid)print('description:%s' % str(item.function.__doc__))print(('运行结果: %s' % report.outcome))@pytest.fixture(scope="session", autouse=True)def fix_a():print("setup 前置操作")yieldprint("teardown 后置操作")
# test_a.pydef test_a():"""用例描述:test_a"""print("123")assert 1 == 0
运行结果:


第五个案例
setup 前置操作函数正常执行,测试用例 call 正常执行, teardown 后置操作函数执行时发生异常。
测试用例正常执行,但是测试结果中会有 error ,因为 teardown 后置操作函数在执行时发生异常
# conftest.pyimport pytest@pytest.hookimpl(hookwrapper=True, tryfirst=True)def pytest_runtest_makereport(item, call):print('------------------------------------')# 获取钩子方法的调用结果out = yieldprint('用例执行结果', out)# 从钩子方法的调用结果中获取测试报告report = out.get_result()print('测试报告:%s' % report)print('步骤:%s' % report.when)print('nodeid:%s' % report.nodeid)print('description:%s' % str(item.function.__doc__))print(('运行结果: %s' % report.outcome))@pytest.fixture(scope="session", autouse=True)def fix_a():print("setup 前置操作")yieldprint("teardown 后置操作")raise Exception("teardown 失败了")
# test_a.pydef test_a():'''用例描述:test_a'''print("123")
运行结果:



第六个案例:只获取call结果
场景:编写测试用例时,在保证 setup 前置操作函数和 teardown 后置操作函数不报错的前提下,我们一般只需要关注测试用例的执行结果,即只需要获取测试用例执行call的结果。
解决办法:因为前面的 pytest_runtest_makereport 钩子方法执行了三次。所以在打印测试报告的相关数据之气可以加个判断: if report.when == "call" 。
import pytestfrom _pytest import runner'''# 对应源码def pytest_runtest_makereport(item, call):""" return a :py:class:`_pytest.runner.TestReport` objectfor the given :py:class:`pytest.Item` and:py:class:`_pytest.runner.CallInfo`."""'''@pytest.hookimpl(hookwrapper=True, tryfirst=True)def pytest_runtest_makereport(item, call):print('------------------------------------')# 获取钩子方法的调用结果out = yield# print('用例执行结果:', out)# 从钩子方法的调用结果中获取测试报告report = out.get_result()if report.when == "call":print('测试报告:%s' % report)print('步骤:%s' % report.when)print('nodeid:%s' % report.nodeid)print('description:%s' % str(item.function.__doc__))print(('运行结果: %s' % report.outcome))@pytest.fixture(scope="session", autouse=True)def fix_a():print("setup 前置操作")yieldprint("teardown 后置操作")
运行结果:


conftest.py 去除pytest_runtest_makereport 钩子方法,正常执行测试用例
# conftest.pyimport pytest@pytest.fixture(scope="session", autouse=True)def fix_a():print("setup 前置操作")yieldprint("teardown 后置操作")
# test_a.pydef test_a():"""用例描述:test_a"""print("123")
运行结果:


最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

相关文章:
pytest系列——pytest_runtest_makereport钩子函数获取测试用例执行结果
前言 pytest测试框架提供的很多钩子函数方便我们对测试框架进行二次开发,可以根据自己的需求进行改造。 例如:钩子方法:pytest_runtest_makereport ,可以更清晰的了解测试用例的执行过程,并获取到每个测试用例的执行…...
Oracle数据库模式对象
文章目录 Oracle数据库模式对象 Oracle数据库模式对象 1、模式(schema)是一个数据库对象的集合。模式为一个数据库用户所有,与用户名字相同。通俗来说,模式对象就是一个用户。 2、 模式对象包括:聚簇、约束、数据库链接、触发器、维、外部过…...
各地户外分散视频监控点位,如何实现远程集中实时监看?
公司业务涉及视频监控项目承包搭建,此前某个项目需求是为某林业公司提供视频监控解决方案,需要实现各地视频摄像头的集中实时监看,以防止国家储备林的盗砍、盗伐行为。 公司原计划采用运营商专线连接各个视频监控点位,实现远程视…...
Vue笔记12-新的组件
Fragment 在Vue2中,template标签内,必须有一个div标签,作为根标签。 在Vue3中,可以没有div根标签,如果没有的话,Vue3会将多个标签包装在一个Fragment虚拟元素里。 这么做的目的:减少标签的层级…...
PySide6开发桌面程序,PySide6入门实战(下)
文章目录 系列文章索引六、样式表qss1、概述2、通用组件常用样式3、QLineEdit组件常用样式4、QpushButton常用样式5、QSlider常用样式6、QComboBox常用样式7、QProgressBar常用样式8、QMenu菜单样式9、qss选择器10、使用qss文件动态加载qss11、QDarkStyle夜间模式12、禁止子窗口…...
Java面试八股之Redis有哪些数据类型?底层实现分别是什么
Redis有哪些数据类型?底层实现分别是什么 Redis数据类型概述 Redis作为一款键值存储系统,提供了丰富多样的数据类型以满足不同场景的需求。以下是Redis支持的主要数据类型及其基本用途: String(字符串) 存储单个键…...
分布式应用系统设计:即时消息系统
即时消息(IM)系统,涉及:站内消息系统 组件如下; 客户端: WEB页面,IM桌面客户端。通过WebSocket 跟ChatService后端服务连接 Chat Service: 提供WebSocket接口,并保持跟“客户端”状态的维护。…...
【YashanDB知识库】调整NUMBER精度,再执行统计信息收集高级包偶现数据库异常退出
【问题分类】功能使用 【关键字】NUMBER类型精度修改,统计信息收集 【问题描述】存量的表将NUMBER类型的字段精度从小精度调整为大精度时,数据库收集这张业务表的统计信息时,会导致数据库异常退出。 【问题原因分析】YashanDB NUMBER字段精…...
ComfyUI+MuseV+MuseTalk图片数字人
电脑配置 GPU12G,如果自己电脑配置不够,选择云gpu,我就是用的这个,自己电脑太老配置跟不上 环境: Python 3.11.8 torch 2.2.1 cuda_12.1 资源提供: 链接:https://pan.baidu.com/s/1_idZbF…...
【Python】从基础到进阶(三):深入了解Python中的运算符与表达式
🔥 个人主页:空白诗 文章目录 一、引言二、运算符1. 算术运算符2. 比较运算符3. 逻辑运算符4. 位运算符5. 赋值运算符6. 其他运算符 三、表达式1. 表达式的定义2. 运算符的优先级3. 使用括号提升可读性4. 组合运算符与复合表达式 四、案例:计…...
C#的DllImport使用方法
1. 托管代码与非托管代码 托管代码:我们编写的C#代码(也包括.net平台上的其他语言,如VB,J#等),首先经过编译器把代码编译成中间语言(IL),当方法被调用时,公共…...
人工智能算法工程师(中级)课程11-PyTorch神经网络之循环神经网络RNN与代码详解
大家好,我是微学AI,今天给大家介绍一下人工智能算法工程师(中级)课程11-PyTorch神经网络之循环神经网络RNN与代码详解。循环神经网络(Recurrent Neural Network,RNN)是一种处理序列数据的神经网络。本文将详细介绍RNN网…...
服务端生成RSA密钥实例
RSA非对称加密算法的一种,这里分享一下服务端生成公钥和私钥的实例,并打印出来。 一:实例代码 package mainimport ("bufio""crypto/rand""crypto/rsa""crypto/x509""encoding/pem"&quo…...
Maven Nexus3 私服搭建、配置、项目发布指南
maven nexus私服搭建 访问nexus3官方镜像库,选择需要的版本下载:Docker Nexus docker pull sonatype/nexus3:3.49.0 创建数据目录并赋权 sudo mkdir /nexus-data && sudo chown -R 200 /nexus-data 运行(数据目录选择硬盘大的卷进行挂载) …...
东方博宜1627 - 暑期的旅游计划(2)
问题描述 期末考试结束了,小华语文、数学、英语三门功课分别考了 x、y、z 分,小华的家长说,如果小华三门功课中有一门考到 90 分或者 90 分以上,那么就去北京旅游,如果都没考到,那么就去南京玩。 请从键盘…...
FastAPI 学习之路(三十五)项目结构优化
之前我们创建的文件都是在一个目录中,但是在我们的实际开发中,肯定不能这样设计,那么我们去创建一个目录,叫models,大致如下。 主要目录是: __init__.py 是一个空文件,说明models是一个package…...
linux源码安装mysql8.0的小白教程
1.下载8.x版本的mysql MySQL :: Download MySQL Community Server (Archived Versions) 2.安装linux 我安装的是Rocky Linux8.6 3.设置ip地址,方便远程连接 使用nmcli或者nmtui设置或修改ip地址 4.使用远程连接工具MobaXterm操作: (1)将mysql8版本的压缩包上传到mybaxterm…...
如何评估独立站的外链质量?
要评估独立站的外链质量时,首先要看的不是别的,而是内容,跟你网站相关的文章内容才是最重要的,其他的一切其实都不重要。什么网站的DA,评级,网站的主要内容跟你的文章内容是否相关其实都不重要,…...
AI在编程领域的作用
AI(人工智能)在软件开发和许多其他领域都发挥着重要作用,但这并不意味着它在取代开发者。相反,AI更多地是在帮助开发者提高工作效率,解决复杂问题,并创造新的可能性。 探讨AI工具对开发者日常工作的影响 …...
医疗器械网络安全 | 漏洞扫描、渗透测试没有发现问题,是否说明我的设备是安全的?
尽管漏洞扫描、模糊测试和渗透测试在评估系统安全性方面是非常重要和有效的工具,但即使这些测试没有发现任何问题,也不能完全保证您的医疗器械是绝对安全的。这是因为安全性的评估是一个多维度、复杂且持续的过程,涉及多个方面和因素。以下是…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
