前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >pytest文档35-Hooks函数之统计测试结果(pytest_terminal_summary)

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

作者头像
上海-悠悠
发布2020-05-07 10:45:59
1.6K0
发布2020-05-07 10:45:59
举报

前言

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

pytest_terminal_summary

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

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

TerminalReporter部分代码

代码语言:javascript
复制
class TerminalReporter(object):
def __init__(self, config, file=None):
import _pytest.configself.config = config
self._numcollected = 0
self._session = None
self._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 None
and self._collect_report_last_write > t - REPORT_COLLECTING_RESOLUTION
):
return
self._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 - deselected
if final:
line = "collected "
else:
line = "collecting "
line += (
str(self._numcollected) + " item" + ("" if self._numcollected == 1 else "s")
)
if errors:
line += " / %d errors" % errors
if deselected:
line += " / %d deselected" % deselected
if skipped:
line += " / %d skipped" % skipped
if self._numcollected > selected > 0:
line += " / %d selected" % selected
if self.isatty:
self.rewrite(line, bold=True, erase=True)
if final:
self.write("\n")
else:
self.write_line(line)

案例参考

先在test_a.py写几个用例

代码语言:javascript
复制
# test_a.py
import pytestdef 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用例参考

代码语言:javascript
复制
# test_b.py
import timedef test_5():
print("测试用例55555555")
time.sleep(3)def test_6():
print("测试用例66666666")
time.sleep(3)
assert 1 == 2

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

代码语言:javascript
复制
import time
from _pytest import terminaldef 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._sessionstarttime
print('total times:', duration, 'seconds')

运行结果

代码语言:javascript
复制
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代码修改下

代码语言:javascript
复制
# 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

重新运行用例,结果如下

代码语言:javascript
复制
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异常情况

代码语言:javascript
复制
# 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

运行结果

代码语言:javascript
复制
{'': [<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 用例

代码语言:javascript
复制
<TestReport 'test_b.py::test_5' when='call' outcome='passed'>

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

代码语言:javascript
复制
'error': [<TestReport 'test_b.py::test_5' when='teardown' outcome='failed'>]

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

修改后的最终代码如下

代码语言:javascript
复制
import time
from _pytest import terminaldef 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._sessionstarttime
print('total times:', duration, 'seconds')

运行后的结果

代码语言:javascript
复制
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 ============
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 从零开始学自动化测试 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • pytest_terminal_summary
  • 案例参考
  • setup和teardown异常情况
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档