【pytest】Hook 方法之 pytest_runtest_makereport:获取测试用例执行结果

Hook 方法之 pytest_runtest_makereport:

@hookspec(firstresult=True)
def pytest_runtest_makereport(item, call):
    """ return a :py:class:`_pytest.runner.TestReport` object
    for 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 次,分别是:

  1. 用例的 setup 执行完毕后,调用 1 次,返回 setup 的执行结果;
  2. 用例执行完毕之后,调用 1 次,返回测试用例的执行结果;
  3. 用例的 teardown 执行完毕后,调用1 次,返回 teardown 的执行结果;

 获取测试用例的执行结果:

准备测试用例:

class TestDemoA:

    def test_A_001(self):
        pass

调用钩子方法: 用不到 call 和 item 参数;

# conftest.py

import pytest

@pytest.fixture(autouse=True)
def fix_result():
    # setup
    print()
    yield
    # teardown
    print()

# 1. 调用钩子方法, item 参数这里不用
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport():
    print('------------------------------------')

    # 2. 获取钩子方法的调用结果
    result = yield
    print('钩子方法的执行结果', result)

    # 3. 从钩子方法的调用结果中获取测试报告
    report = result.get_result()

    print('从结果中获取测试报告:', report)
    print('从报告中获取 nodeid:', report.nodeid)
    print('从报告中获取调用步骤:', report.when)
    print('从报告中获取执行结果:', report.outcome)

if __name__ == '__main__':
    pytest.main(['-s', '-q'])

执行结果:

从结果中我们可以看到每次调用返回的 Result 对象和 TestReport对象,以及对象属性;

对象属性就是我们想要的信息;

当setup、测试用例、teardown 执行失败时的结果:

测试用例:修改为断言失败;

class TestDemoA:

    def test_A_001(self):
        # 断言失败
        assert 0

调用钩子方法:精简一下代码;

修改 fixture:控制 setup 和 teardown 执行失败;

# conftest.py

import pytest

# P=100 时 setup 失败;
# P=1000时 teardown 失败;
P = 100

@pytest.fixture(autouse=True)
def fix_result():
    global P
    if P == 100:
        raise Exception('fixture setup 执行出错!')
    yield
    if P == 100:
        raise Exception('fixture teardown 执行出错!')

# 1. 调用钩子方法, item 参数这里不用
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport():
    print()
    print('------------------------------------')

    # 2. 获取钩子方法的调用结果
    result = yield
    print('钩子方法的执行结果', result)

    # 3. 从钩子方法的调用结果中获取测试报告
    report = result.get_result()

    print('当前用例的 nodeid:', report.nodeid)
    print('当前用例执行步骤:', report.when)
    print('执行结果:', report.outcome)

当 setup 失败时执行结果:

 从结果上看:
setup 的执行结果是 failed,但是没有用例本身的执行结果,而且 teardown 的结果竟然是 passed; 这是因为pytest 有个规则,就是当 setup 执行失败时后面的测试用例和 teardown 就不会再执行,所以没有这次没有输出测试用例的执行结果,而且因为 teardown 没有执行,所以teardown 的结果没有失败(虽然不知道是为什么,感觉这是个bug!)

当 setup 成功,测试用例和teardown 失败时执行结果:

这次就正常了,步骤 call 就是测试用例本身的结果;

实际应用:获取用例执行结果处理用例依赖:

因为部分用例必须依赖前面某个用例,当前置用例失败后,后续用例必定会失败并且非常耗时,所以我们可以用这个钩子方法来处理这个问题,跳过依赖的用例;

# conftest.py

import pytest

# 定义一个类,来存储用例执行失败的结果
class Falied:
    skip = False


@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport():
    result = yield
    report = result.get_result()

    # 当前用例名
    case_name = report.nodeid.split('::')[-1]

    # 当某个用例失败时(setup失败也算)或被跳过时,将这个用例的执行结果存储在 Failed 类中
    if report.when in ('setup', 'call') and report.outcome in ('failed', 'skipped'):
        setattr(Falied, case_name, True)

if __name__ == '__main__':
    pytest.main(['-s', '-q'])
import pytest
from .conftest import Falied


class TestDemoA:

    def test_A_001(self):
        # 断言失败
        assert 0

    def test_A_002(self):
        # 从 Failed 获取 test_A_001 的执行结果
        if getattr(Falied, 'test_A_001', False):
            pytest.skip('test_A_001 执行失败或被跳过,此用例跳过!')

    def test_A_003(self):
        pass

测试结果:因为 case 001 执行失败,所以 case 002 被跳过;

============================= test session starts =============================
collected 3 items

test_Z.py::TestDemoA::test_A_001 FAILED
test_Z.py::TestDemoA::test_A_002 SKIPPED
test_Z.py::TestDemoA::test_A_003 PASSED

=================== 1 failed, 1 passed, 1 skipped in 0.05s ====================

 

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值