pytest提供的钩子(Hooks)方法之pytest_runtest_makereport,可以更清晰的了解用例的执行过程,并获取到每个用例的执行结果。
一、Hook 方法之 pytest_runtest_makereport源码:
@hookspec(firstresult=True)
def pytest_runtest_makereport(item, call):""" return a :py:class:`_pytest.runner.TestReport` objectfor the given :py:class:`pytest.Item <_pytest.main.Item>` and:py:class:`_pytest.runner.CallInfo`.Stops at first non-None result, see :ref:`firstresult` """
二、作用:
对于给定的测试用例(item)和调用步骤(call),返回一个测试报告对象(_pytest.runner.TestReport);
具体表现为:这个钩子方法会被每个测试用例调用 3 次,分别是:
用例的 setup 执行完毕后,调用 1 次,返回 setup 的执行结果;
用例执行完毕之后,调用 1 次,返回测试用例的执行结果;
用例的 teardown 执行完毕后,调用1 次,返回 teardown 的执行结果;
三、conftest.py写入pytest_runtest_makereport 内容如下:
import 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)
四、test01.py写入测试用例如下:
#!/usr/bin/env python
# _*_coding:utf-8_*_import pytestclass Test(object):def setup(self):print("setup前置操作")def teardown(self):print("teardown后置操作")def test_01(self):"""用例描述"""print("用例1——橙子")if __name__ == '__main__':pytest.main(["-s", "test01.py"])
用例执行后如下:
运行结果如下:
"C:\Program Files\Python35\python.exe" C:/Users/wangli/PycharmProjects/Test/test/test01.py
============================= test session starts =============================
platform win32 -- Python 3.5.2, pytest-5.1.2, py-1.8.0, pluggy-0.12.0
rootdir: C:\Users\wangli\PycharmProjects\Test\test
plugins: allure-pytest-2.8.5, html-1.22.0, metadata-1.8.0, rerunfailures-8.0
collected 1 itemtest01.py setup前置操作
——————————————————————————
用例执行结果 <pluggy.callers._Result object at 0x000002436AA8D898>
测试报告:<TestReport 'test01.py::Test::test_01' when='setup' outcome='passed'>
步骤:setup
nodeid:test01.py::Test::test_01
description:用例描述
执行结果: passed
用例1——橙子
——————————————————————————
用例执行结果 <pluggy.callers._Result object at 0x000002436AA8D898>
测试报告:<TestReport 'test01.py::Test::test_01' when='call' outcome='passed'>
步骤:call
nodeid:test01.py::Test::test_01
description:用例描述
执行结果: passed
.teardown后置操作
——————————————————————————
用例执行结果 <pluggy.callers._Result object at 0x000002436AA8D898>
测试报告:<TestReport 'test01.py::Test::test_01' when='teardown' outcome='passed'>
步骤:teardown
nodeid:test01.py::Test::test_01
description:用例描述
执行结果: passed============================== 1 passed in 0.03s ==============================
五、setup失败情况
当setup执行失败了,setup的执行结果的failed,后面的call用例和teardown都不会执行了,最终执行结果是error
#!/usr/bin/env python
# _*_coding:utf-8_*_import pytestclass Test(object):def setup(self):print("setup前置操作")raise Exception("setup执行失败了")def teardown(self):print("teardown后置操作")def test_01(self):"""用例描述"""print("用例1——橙子")if __name__ == '__main__':pytest.main(["-s", "test01.py"])"C:\Program Files\Python35\python.exe" C:/Users/wangli/PycharmProjects/Test/test/test01.py
============================= test session starts =============================
platform win32 -- Python 3.5.2, pytest-5.1.2, py-1.8.0, pluggy-0.12.0
rootdir: C:\Users\wangli\PycharmProjects\Test\test
plugins: allure-pytest-2.8.5, html-1.22.0, metadata-1.8.0, rerunfailures-8.0
collected 1 itemtest01.py setup前置操作
——————————————————————————
用例执行结果 <pluggy.callers._Result object at 0x000001CD851B9630>
测试报告:<TestReport 'test01.py::Test::test_01' when='setup' outcome='failed'>
步骤:setup
nodeid:test01.py::Test::test_01
description:用例描述
执行结果: failed
E——————————————————————————
用例执行结果 <pluggy.callers._Result object at 0x000001CD851B9518>
测试报告:<TestReport 'test01.py::Test::test_01' when='teardown' outcome='passed'>
步骤:teardown
nodeid:test01.py::Test::test_01
description:用例描述
执行结果: passed=================================== ERRORS ====================================
_______________________ ERROR at setup of Test.test_01 ________________________self = <test.test01.Test object at 0x000001CD851B1780>def setup(self):print("setup前置操作")
> raise Exception("setup执行失败了")
E Exception: setup执行失败了test01.py:10: Exception
============================== 1 error in 0.11s ===============================
六、用例断言失败,用例结果是failed,setup和teardown都是pass的,最终执行结果是failed
#!/usr/bin/env python
# _*_coding:utf-8_*_import pytestclass Test(object):def setup(self):print("setup前置操作")def teardown(self):print("teardown后置操作")def test_01(self):"""用例描述"""print("用例1——橙子")assert 0if __name__ == '__main__':pytest.main(["-s", "test01.py"])"C:\Program Files\Python35\python.exe" C:/Users/wangli/PycharmProjects/Test/test/test01.py
============================= test session starts =============================
platform win32 -- Python 3.5.2, pytest-5.1.2, py-1.8.0, pluggy-0.12.0
rootdir: C:\Users\wangli\PycharmProjects\Test\test
plugins: allure-pytest-2.8.5, html-1.22.0, metadata-1.8.0, rerunfailures-8.0
collected 1 itemtest01.py setup前置操作
——————————————————————————
用例执行结果 <pluggy.callers._Result object at 0x00000251E9988550>
测试报告:<TestReport 'test01.py::Test::test_01' when='setup' outcome='passed'>
步骤:setup
nodeid:test01.py::Test::test_01
description:用例描述
执行结果: passed
用例1——橙子
——————————————————————————
用例执行结果 <pluggy.callers._Result object at 0x00000251E990E2B0>
测试报告:<TestReport 'test01.py::Test::test_01' when='call' outcome='failed'>
步骤:call
nodeid:test01.py::Test::test_01
description:用例描述
执行结果: failed
Fteardown后置操作
——————————————————————————
用例执行结果 <pluggy.callers._Result object at 0x00000251E990E470>
测试报告:<TestReport 'test01.py::Test::test_01' when='teardown' outcome='passed'>
步骤:teardown
nodeid:test01.py::Test::test_01
description:用例描述
执行结果: passed================================== FAILURES ===================================
________________________________ Test.test_01 _________________________________self = <test.test01.Test object at 0x00000251E9981748>def test_01(self):"""用例描述"""print("用例1——橙子")
> assert 0
E AssertionErrortest01.py:17: AssertionError
============================== 1 failed in 0.15s ==============================
七、teardown执行失败了,teardown的执行结果的failed,setup和case都是pass的,最终执行结果是1 passed,1 error
#!/usr/bin/env python
# _*_coding:utf-8_*_import pytestclass Test(object):def setup(self):print("setup前置操作")def teardown(self):print("teardown后置操作")assert 0def test_01(self):"""用例描述"""print("用例1——橙子")if __name__ == '__main__':pytest.main(["-s", "test01.py"])"C:\Program Files\Python35\python.exe" C:/Users/wangli/PycharmProjects/Test/test/test01.py
============================= test session starts =============================
platform win32 -- Python 3.5.2, pytest-5.1.2, py-1.8.0, pluggy-0.12.0
rootdir: C:\Users\wangli\PycharmProjects\Test\test
plugins: allure-pytest-2.8.5, html-1.22.0, metadata-1.8.0, rerunfailures-8.0
collected 1 itemtest01.py setup前置操作
——————————————————————————
用例执行结果 <pluggy.callers._Result object at 0x000001A7DF259588>
测试报告:<TestReport 'test01.py::Test::test_01' when='setup' outcome='passed'>
步骤:setup
nodeid:test01.py::Test::test_01
description:用例描述
执行结果: passed
用例1——橙子
——————————————————————————
用例执行结果 <pluggy.callers._Result object at 0x000001A7DF259588>
测试报告:<TestReport 'test01.py::Test::test_01' when='call' outcome='passed'>
步骤:call
nodeid:test01.py::Test::test_01
description:用例描述
执行结果: passed
.teardown后置操作
——————————————————————————
用例执行结果 <pluggy.callers._Result object at 0x000001A7DF1DE9B0>
测试报告:<TestReport 'test01.py::Test::test_01' when='teardown' outcome='failed'>
步骤:teardown
nodeid:test01.py::Test::test_01
description:用例描述
执行结果: failed
E=================================== ERRORS ====================================
______________________ ERROR at teardown of Test.test_01 ______________________self = <test.test01.Test object at 0x000001A7DF251780>def teardown(self):print("teardown后置操作")
> assert 0
E AssertionErrortest01.py:13: AssertionError
========================= 1 passed, 1 error in 0.12s ==========================