Pytest中提供了很多钩子函数,可以方便我们基于此进行二次开发,另外通过对Pytest钩子函数的学习,我们也能够更好的理解到其在用例执行的各阶段到底做了哪些工作。
今天我们将学习Pytest中的钩子函数:pytest_runtest_makereport
,它可以让我们获取到用例执行结果。
钩子函数的使用
我们可以在Pytest源码中的 runner.py
文件下找到 pytest_runtest_makereport()
钩子函数,大致如下:
def pytest_runtest_makereport(item, call):
return TestReport.from_item_and_call(item, call)
该函数操作时传入 测试用例 item 和 测试步骤 call,返回的数据是测试用例的执行结果。下面是简单的示例:
# test_01.py
import pytest
def test_01():
"""用例描述:XXXXXX"""
print("测试一下")
assert 1
# conftest.py
import pytest
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call):
print("------------------------Start---------------------------")
out = yield
res = out.get_result()
print("执行结果:{}".format(res))
print("测试用例:{}".format(item))
print("测试步骤:{}".format(call))
print("------------------------End---------------------------")
把上面的用例执行后,得到如下结果:
从上方输出的信息可以知道,我们在 Pytest 中执行一条用例的时候,需要经过以下3个阶段:
- 最先执行
when='setup'
的前置操作- 接着执行
when='call'
的用例部分- 最后执行
when='teardown'
的后置操作
上面的每一个阶段,都会返回相应的执行结果,如果用例中不存在前置/后置操作,那么该阶段默认 outcome='passed'
。
当然对于这3个阶段,也都可能会出现失败的情况。为了更方便模拟操作失败的情况,我们在 conftest.py
中使用 fixture
增加一个函数,然后设置为自动调用。
@pytest.fixture(scope="function", autouse=True)
def setup_teardown():
print("------------------------这是setup前置操作---------------------------")
yield
print("------------------------这是teardown后置操作---------------------------")
setup前置操作失败
为了让用例在前置操作中出现失败,我们可以简单修改下 conftest.py
代码:
@pytest.fixture(scope="function", autouse=True)
def setup_teardown():
assert 0
print("------------------------这是setup前置操作---------------------------")
yield
print("------------------------这是teardown后置操作---------------------------")
然后重新运行用例,得到结果如下:
从用例结果中可以看到,我们在 Pytest 中执行用例时,如果在setup前置操作中就出现失败,那么其不会再调用测试用例和执行后置操作(上面 teardown 的信息也没有打印出来),而用例的执行结果为:error
。
call测试用例失败
为了让用例在 call 调用中出现失败,我们可以简单修改下 test_01.py
代码:
import pytest
def test_01():
"""用例描述:XXXXXX"""
print("断言失败")
assert 0
重新运行用例,得到结果如下:
从用例结果中可以看到,我们在 Pytest 中执行用例时,setup前置操作成功,但在call测试用例中出现失败,那么其会继续执行后置操作,最后用例的执行结果为:failed
。
teardown后置操作失败
为了让用例在前置操作中出现失败,我们可以简单修改下 conftest.py
代码:
@pytest.fixture(scope="function", autouse=True)
def setup_teardown():
print("------------------------这是setup前置操作---------------------------")
yield
print("------------------------这是teardown前置操作---------------------------")
assert 0
重新运行用例,得到结果如下:
从用例结果中可以看到,我们在 Pytest 中执行用例时,teardown后置操作失败,那么最后用例的结果为:1 passed, 1 error
。
获取用例执行时的信息
有时候,我们想要获取测试用例执行的详细信息,比如打印用例描述,或在用例执行失败后打印日志等信息,那么我们可以优化下代码:
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call):
print("------------------------Start---------------------------")
out = yield # 钩子函数的调用结果
res = out.get_result() # 获取用例执行结果
print("执行结果:{}".format(res))
if res.when == "call" and res.outcome == "failed": # 只获取call用例失败时的信息
print("测试用例:{}".format(item))
print("用例描述:{}".format(item.function.__doc__))
print("测试步骤:{}".format(call))
print("用例失败异常信息:{}".format(call.excinfo))
print("用例失败时的详细日志:{}".format(res.longrepr))
print("------------------------End---------------------------")
重新运行用例,得到结果如下: