pytest文档35-Hooks函数之统计测试结果(pytest_terminal_summary)

 前言

用例执行完成后,我们希望能获取到执行的结果,这样方便我们快速统计用例的执行情况。
也可以把获取到的结果当成总结报告,发邮件的时候可以先统计测试结果,再加上html的报告。

pytest_terminal_summary

关于TerminalReporter类可以在_pytest.terminal中查看到

from _pytest import terminalpytest_terminal_summary(terminalreporter, exitstatus, config)
最后的结果汇总,可以拿到所有的执行结果
参数:
- terminalreporter (_pytest.terminal.TerminalReporter) – 内部使用的终端测试报告对象
- exitstatus (int) – 返回给操作系统的返回码
- config(_pytest.config.Config) - pytest config对象

TerminalReporter部分代码

class TerminalReporter(object):def __init__(self, config, file=None):import _pytest.configself.config = configself._numcollected = 0self._session = Noneself._showfspath = Noneself.stats = {}self.startdir = config.invocation_dirdef report_collect(self, final=False):if self.config.option.verbose < 0:returnif not final:# Only write "collecting" report every 0.5s.t = time.time()if (self._collect_report_last_write is not Noneand self._collect_report_last_write > t - REPORT_COLLECTING_RESOLUTION):returnself._collect_report_last_write = terrors = len(self.stats.get("error", []))skipped = len(self.stats.get("skipped", []))deselected = len(self.stats.get("deselected", []))selected = self._numcollected - errors - skipped - deselectedif final:line = "collected "else:line = "collecting "line += (str(self._numcollected) + " item" + ("" if self._numcollected == 1 else "s"))if errors:line += " / %d errors" % errorsif deselected:line += " / %d deselected" % deselectedif skipped:line += " / %d skipped" % skippedif self._numcollected > selected > 0:line += " / %d selected" % selectedif self.isatty:self.rewrite(line, bold=True, erase=True)if final:self.write("\n")else:self.write_line(line)

案例参考

先在test_a.py写几个用例

# test_a.py
import pytest
# 上海-悠悠def test_1():print("测试用例1111")assert 1 == 1@pytest.mark.skip("跳过")
def test_2():print("测试用例22222")assert 1 == 1def test_3():print("测试用例3333")def test_4():print("测试用例44444444")assert 1 == 2

test_b.py用例参考

# test_b.py
import time
# 上海-悠悠def test_5():print("测试用例55555555")time.sleep(3)def test_6():print("测试用例66666666")time.sleep(3)assert 1 == 2

于是在conftest.py中写个 pytest_terminal_summary 函数收集测试结果

import time
from _pytest import terminal
# 上海-悠悠def pytest_terminal_summary(terminalreporter, exitstatus, config):'''收集测试结果'''print(terminalreporter.stats)print("total:", terminalreporter._numcollected)print('passed:', len(terminalreporter.stats.get('passed', [])))print('failed:', len(terminalreporter.stats.get('failed', [])))print('error:', len(terminalreporter.stats.get('error', [])))print('skipped:', len(terminalreporter.stats.get('skipped', [])))# terminalreporter._sessionstarttime 会话开始时间duration = time.time() - terminalreporter._sessionstarttimeprint('total times:', duration, 'seconds')

运行结果

D:\soft\pytest_xuexi_demo>pytest
============================= test session starts =============================
platform win32 -- Python 3.6.0, pytest-4.5.0, py-1.5.4, pluggy-0.13.1
rootdir: D:\soft\pytest_xuexi_demo
plugins: allure-pytest-2.8.6, PyTestReport-0.1.9.3, forked-0.2, html-1.19.0, metadata-1.7.0, repeat-0.7.0, rerunfailures-8.0, xdist-1.23.2
collected 6 itemstest_a.py .s.F                                                           [ 66%]
test_b.py .F                                                             [100%]================================== FAILURES ===================================
___________________________________ test_4 ____________________________________def test_4():print("测试用例44444444")
>       assert 1==2
E       assert 1 == 2test_a.py:21: AssertionError
---------------------------- Captured stdout call -----------------------------
测试用例44444444
___________________________________ test_6 ____________________________________def test_6():print("测试用例66666666")time.sleep(3)
>       assert 1 == 2
E       assert 1 == 2test_b.py:18: AssertionError
---------------------------- Captured stdout call -----------------------------
测试用例66666666
{'': [<TestReport 'test_a.py::test_1' when='setup' outcome='passed'>, <TestReport 'test_a.py::test_1' when='teardown' outcome='passed'>, <TestReport 'test_a.py::test_2' when='teardown' outcome='passed'>, <TestReport 'test_a.py::test_3' when='setup' outcome='passed'>, <TestReport 'test_a.py::test_3' when='teardown' outcome='passed'>, <TestReport 'test_a.py::test_4' when='setup' outcome='passed'>, <TestReport 'test_a.py::test_4' when='teardown' outcome='passed'>, <TestReport 'test_b.py::test_5' when='setup' outcome='passed'>, <TestReport 'test_b.py::test_5' when='teardown' outcome='passed'>, <TestReport 'test_b.py::test_6' when='setup' outcome='passed'>, <TestReport 'test_b.py::test_6' when='teardown' outcome='passed'>], 'passed': [<TestReport 'test_a.py::test_1' when='call' outcome='passed'>, <TestReport 'test_a.py::test_3' when='call' outcome='passed'>, <TestReport 'test_b.py::test_5' when='call' outcome='passed'>], 'skipped': [<TestReport 'test_a.py::test_2' when='setup' outcome='skipped'>], 'failed': [<TestReport 'test_a.py::test_4' when='call' outcome='failed'>, <TestReport 'test_b.py::test_6' when='call' outcome='failed'>]}
total: 6
passed: 3
failed: 2
error: 0
skipped: 1
total times: 6.150860786437988 seconds
================ 2 failed, 3 passed, 1 skipped in 6.15 seconds ================

setup和teardown异常情况

如果setup出现异常,test_b.py代码修改下

# test_b.py
import time
import pytest
# 上海-悠悠@pytest.fixture(scope="function")
def setup_demo():raise TypeError("ERROR!")def test_5(setup_demo):print("测试用例55555555")time.sleep(3)def test_6():print("测试用例66666666")time.sleep(3)assert 1 == 2

重新运行用例,结果如下

total: 6
passed: 2
failed: 2
error: 1
skipped: 1
成功率:33.33%
total times: 3.1817877292633057 seconds
=========== 2 failed, 2 passed, 1 skipped, 1 error in 3.18 seconds ============

此时统计结果没什么问题,接下来看teardown异常情况

# test_b.py
import time
import pytest
# 上海-悠悠@pytest.fixture(scope="function")
def setup_demo():yield raise TypeError("ERROR!")def test_5(setup_demo):print("测试用例55555555")time.sleep(3)def test_6():print("测试用例66666666")time.sleep(3)assert 1 == 2

运行结果

{'': [<TestReport 'test_a.py::test_1' when='setup' outcome='passed'>, <TestReport 'test_a.py::test_1' when='teardown' outcome='passed'>, <TestReport 'test_a.py::test_2' when='teardown' outcome='passed'>, <TestReport 'test_a.py::test_3' when='setup' outcome='passed'>, <TestReport 'test_a.py::test_3' when='teardown' outcome='passed'>, <TestReport 'test_a.py::test_4' when='setup' outcome='passed'>, <TestReport 'test_a.py::test_4' when='teardown' outcome='passed'>, <TestReport 'test_b.py::test_5' when='setup' outcome='passed'>, <TestReport 'test_b.py::test_6' when='setup' outcome='passed'>, <TestReport 'test_b.py::test_6' when='teardown' outcome='passed'>], 'passed': [<TestReport 'test_a.py::test_1' when='call' outcome='passed'>, <TestReport 'test_a.py::test_3' when='call' outcome='passed'>, <TestReport 'test_b.py::test_5' when='call' outcome='passed'>], 'skipped': [<TestReport 'test_a.py::test_2' when='setup' outcome='skipped'>], 'failed': [<TestReport 'test_a.py::test_4' when='call' outcome='failed'>, <TestReport 'test_b.py::test_6' when='call' outcome='failed'>], 'error': [<TestReport 'test_b.py::test_5' when='teardown' outcome='failed'>]}
total: 6
passed: 3
failed: 2
error: 1
skipped: 1
成功率:50.00%
total times: 6.18759298324585 seconds
=========== 2 failed, 3 passed, 1 skipped, 1 error in 6.19 seconds ============

这个时候总用例是6,但是2 failed, 3 passed, 1 skipped, 1 error加起来的个数是7,这个为什么?

从 terminalreporter.stats 可以看出 passed 里面 when='call' 时候统计了一次 test_5 用例

<TestReport 'test_b.py::test_5' when='call' outcome='passed'>

error 里面 when='teardown' 又统计了一次 test_5 用例

'error': [<TestReport 'test_b.py::test_5' when='teardown' outcome='failed'>]

when='teardown' 是测试用例的后置操作,一般用于数据的清理,报错了的话不影响测试用例的执行结果,所以可以忽略掉

修改后的最终代码如下

import time
from _pytest import terminal
# 上海-悠悠def pytest_terminal_summary(terminalreporter, exitstatus, config):'''收集测试结果'''# print(terminalreporter.stats)print("total:", terminalreporter._numcollected)print('passed:', len([i for i in terminalreporter.stats.get('passed', []) if i.when != 'teardown']))print('failed:', len([i for i in terminalreporter.stats.get('failed', []) if i.when != 'teardown']))print('error:', len([i for i in terminalreporter.stats.get('error', []) if i.when != 'teardown']))print('skipped:', len([i for i in terminalreporter.stats.get('skipped', []) if i.when != 'teardown']))print('成功率:%.2f' % (len(terminalreporter.stats.get('passed', []))/terminalreporter._numcollected*100)+'%')# terminalreporter._sessionstarttime 会话开始时间duration = time.time() - terminalreporter._sessionstarttimeprint('total times:', duration, 'seconds')

运行后的结果

total: 6
passed: 3
failed: 2
error: 0
skipped: 1
成功率:50.00%
total times: 6.20133113861084 seconds
=========== 2 failed, 3 passed, 1 skipped, 1 error in 6.20 seconds ============

拿到测试结果

很多小伙伴问到如何拿到测试结果,这里我把测试结果保存为txt文件,你们也可以保存json文件

import time
from _pytest import terminal
# 111
# blog地址 https://www.cnblogs.com/yoyoketang/def pytest_terminal_summary(terminalreporter, exitstatus, config):'''收集测试结果'''# print(terminalreporter.stats)total = terminalreporter._numcollectedpassed= len([i for i in terminalreporter.stats.get('passed', []) if i.when != 'teardown'])failed=len([i for i in terminalreporter.stats.get('failed', []) if i.when != 'teardown'])error=len([i for i in terminalreporter.stats.get('error', []) if i.when != 'teardown'])skipped=len([i for i in terminalreporter.stats.get('skipped', []) if i.when != 'teardown'])successful = len(terminalreporter.stats.get('passed', []))/terminalreporter._numcollected*100# terminalreporter._sessionstarttime 会话开始时间duration = time.time() - terminalreporter._sessionstarttimeprint('total times: %.2f' % duration, 'seconds')with open("result.txt", "w") as fp:fp.write("TOTAL=%s" % total+"\n")fp.write("PASSED=%s" % passed+"\n")fp.write("FAILED=%s" % failed+"\n")fp.write("ERROR=%s" % error+"\n")fp.write("SKIPPED=%s" % skipped+"\n")fp.write("SUCCESSFUL=%.2f%%" % successful+"\n")fp.write("TOTAL_TIMES=%.2fs" % duration)

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你! 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux网络文件共享服务

目录 一.文件存储类型 1.直连式存储&#xff1a;Direct-Attached Storage&#xff0c;简称DAS 2.存储区域网络&#xff1a;Storage Area Network&#xff0c;简称SAN&#xff08;可以使用空间&#xff0c;管理也是你来管理&#xff09; 3.网络附加存储&#xff1a;Network-…

马季徒孙李寅飞透露:央视春晚相声有岳云鹏、金霏陈曦、卢鑫玉浩

♥ 为方便您进行讨论和分享&#xff0c;同时也为能带给您不一样的参与感。请您在阅读本文之前&#xff0c;点击一下“关注”&#xff0c;非常感谢您的支持&#xff01; 文|猴哥聊娱乐 编辑|侯欢庭 在相声界&#xff0c;有一位备受瞩目的小天才&#xff0c;他就是李寅飞。他不…

多线程排序(java版)

&#x1f4d1;前言 本文主要是【排序】——多线程排序的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日一句&#x…

寒假刷题-递归与递推

寒假刷题 92. 递归实现指数型枚举 解法1递归 使用递归对每一个坑位进行选择&#xff0c;每个坑位有两种选择&#xff0c;填或者不填&#xff0c;使用st数组来记录每个坑位的状态&#xff0c;u来记录已经有多少坑位有了选择。 每个坑位有2钟选择&#xff0c;n个坑位的复杂度就…

python脚本多个文件夹下多个文件中sql语句片段比对

一、需求&#xff1a; 日常测试授权脚本&#xff0c;需要检查多个行业文件夹下单独的授权脚本和汇总授权脚本&#xff0c;一个文件根目录下有多个子文件夹&#xff0c;子文件夹下有多个sql文件&#xff0c;人为比对较为耗时。 需要实现在文件中找到某个sql语句片段&#xff0c…

ChatGPT 和文心一言,各有优劣

目录 前言 具体比较 智能回复能力 语言准确性 知识库丰富度 生成内容风格 总结 前言 近年来&#xff0c;随着人工智能技术的不断进步&#xff0c;AI助手已成为人机交互的重要载体。其中代表性的两个AI助手系统分别是OpenAI推出的ChatGPT,以及腾讯研发的文心一言。这两个…

mysql 为大表新增字段或索引

1 问题 mysql 为大表增加或增加索引等操作时&#xff0c;直接操作原表可能会因为执行超时而导致失败。解决办法如下。 2 解决办法 &#xff08;1&#xff09;建新表-复制表A 的数据结构&#xff0c;不复制数据 create table B like A; &#xff08;2&#xff09;加字段或索…

SCSI/UFS储存架构/协议/电源管理/命令处理流程

UFS子系统架构 1.UFS协议 无论是ufs host controller部分还是ufs device部分&#xff0c;他们都将遵循统一的UFS规范 UFS Application Layer(UAP)应用层 1.UFS command set (UCS) UCS处理命令集&#xff0c;如读、写命令等&#xff0c;.使用的命令是简化的SCSI命令&#xff08;…

枚举类型缝缝补补

✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;橘橙黄又青-CSDN博客 1.关键字enum的定义 enum是C语言中的一个关键字&#xff0c;enum叫枚举数据类型&#…

【数据结构】哈希表详解,举例说明 java中的 HashMap、HashTable及其区别

一、哈希表&#xff08;Hash Table&#xff09;简介&#xff1a; 哈希表是一种数据结构&#xff0c;用于实现字典或映射等抽象数据类型。它通过把关键字映射到表中的一个位置来实现快速的数据检索。哈希表的基本思想是利用哈希函数将关键字映射到数组的索引位置上&#xff0c;…

Android WorkManager入门(二)

WorkManager入门 上一篇前言创建 WorkRequest并提交 定时的任务&#xff08;PeriodicWorkRequest&#xff09;配合约束使用定义执行范围失败后的重试为WorkRequest打上TAG其他取消方法 传参和返回参数总结参考资料 上一篇 Android WorkManager入门&#xff08;一&#xff09; …

GZ036 区块链技术应用赛项赛题第3套

2023年全国职业院校技能大赛 高职组 “区块链技术应用” 赛项赛卷&#xff08;3卷&#xff09; 任 务 书 参赛队编号&#xff1a; 背景描述 新能源作为新兴领域&#xff0c;产业呈现碎片化与复杂化的特性&#xff0c;逐渐出现管理困难、供应链金融、可信监管与数…