前言
pytest提供的很多鈎子(Hooks)方法方便我們對測試用例框架進行二次開發,可以根據自己的需求進行改造。
先學習下pytest_runtest_makereport這個鈎子方法,可以更清晰的了解用例的執行過程,並獲取到每個用例的執行結果。
pytest_runtest_makereport
先看下相關的源碼,在_pytest/runner.py
下,可以導入之后,點進去查看
from _pytest import runner
# 對應源碼
def pytest_runtest_makereport(item, call):
""" return a :py:class:`_pytest.runner.TestReport` object
for the given :py:class:`pytest.Item` and
:py:class:`_pytest.runner.CallInfo`.
"""
這里item是測試用例,call是測試步驟,具體執行過程如下:
- 先執行when='setup' 返回setup 的執行結果
- 然后執行when='call' 返回call 的執行結果
- 最后執行when='teardown'返回teardown 的執行結果
運行案例
conftest.py 寫 pytest_runtest_makereport 內容,打印運行過程和運行結果
# conftest.py
import pytest
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call):
print('------------------------------------')
# 獲取鈎子方法的調用結果
out = yield
print('用例執行結果', 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))
test_a.py寫一個簡單的用例
def test_a():
'''用例描述:test_a'''
print("上海-悠悠")
運行結果如下
D:\soft\code\pytest_jenkins_demo\demo>pytest -s
============================= test session starts =============================
platform win32 -- Python 3.6.0, pytest-4.5.0, py-1.5.4, pluggy-0.13.1
rootdir: D:\demo
plugins: html-1.19.0,
collected 1 item
test_a.py ------------------------------------
用例執行結果 <pluggy.callers._Result object at 0x0000027C547332B0>
測試報告:<TestReport 'test_a.py::test_a' when='setup' outcome='passed'>
步驟:setup
nodeid:test_a.py::test_a
description:用例描述:test_a
運行結果: passed
上海-悠悠
------------------------------------
用例執行結果 <pluggy.callers._Result object at 0x0000027C547332B0>
測試報告:<TestReport 'test_a.py::test_a' when='call' outcome='passed'>
步驟:call
nodeid:test_a.py::test_a
description:用例描述:test_a
運行結果: passed
.------------------------------------
用例執行結果 <pluggy.callers._Result object at 0x0000027C54750A20>
測試報告:<TestReport 'test_a.py::test_a' when='teardown' outcome='passed'>
步驟:teardown
nodeid:test_a.py::test_a
description:用例描述:test_a
運行結果: passed
========================== 1 passed in 0.06 seconds ===========================
從運行結果可以看出,運行用例的過程會經歷三個階段:setup-call-teardown,每個階段都會返回的 Result 對象和 TestReport 對象,以及對象屬性。
setup和teardown上面的用例默認都沒有,結果都是passed。
setup和teardown
給用例寫個fixture增加用例的前置和后置操作,conftest.py內容如下
import pytest
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call):
print('------------------------------------')
# 獲取鈎子方法的調用結果
out = yield
print('用例執行結果', 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))
@pytest.fixture(scope="session", autouse=True)
def fix_a():
print("setup 前置操作")
yield
print("teardown 后置操作")
運行結果如下
setup失敗情況
當setup執行失敗了,setup的執行結果的failed,后面的call用例和teardown都不會執行了
此時用例的狀態是:error, 也就是用例(call)都還沒開始執行,就異常了。
call失敗情況
如果setup正常執行,但是測試用例call失敗了
@pytest.fixture(scope="session", autouse=True)
def fix_a():
print("setup 前置操作")
yield
print("teardown 后置操作")
test_a.py用例
def test_a():
'''用例描述:test_a'''
print("上海-悠悠")
assert 1==0
那么此時運行的結果就是failed
teardown失敗了
如果setup正常執行,測試用例call正常執行,teardown失敗了,這種情況
@pytest.fixture(scope="session", autouse=True)
def fix_a():
print("setup 前置操作")
yield
print("teardown 后置操作")
raise Exception("teardown 失敗了")
teat_a.py用例
def test_a():
'''用例描述:test_a'''
print("上海-悠悠")
最終統計的結果: 1 passed, 1 error in 0.16 seconds
只獲取call的結果
我們在寫用例的時候,如果保證setup和teardown不報錯情況,只關注測試用例本身的運行結果,前面的 pytest_runtest_makereport 鈎子方法執行了三次。
可以加個判斷:if report.when == "call"
import pytest
from _pytest import runner
'''
# 對應源碼
def pytest_runtest_makereport(item, call):
""" return a :py:class:`_pytest.runner.TestReport` object
for the given :py:class:`pytest.Item` and
:py:class:`_pytest.runner.CallInfo`.
"""
'''
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call):
print('------------------------------------')
# 獲取鈎子方法的調用結果
out = yield
# print('用例執行結果', out)
# 3. 從鈎子方法的調用結果中獲取測試報告
report = out.get_result()
if report.when == "call":
print('測試報告:%s' % report)
print('步驟:%s' % report.when)
print('nodeid:%s' % report.nodeid)
print('description:%s' % str(item.function.__doc__))
print(('運行結果: %s' % report.outcome))
@pytest.fixture(scope="session", autouse=True)
def fix_a():
print("setup 前置操作")
yield
print("teardown 后置操作")
運行結果