pytest文檔33-Hooks函數獲取用例執行結果(pytest_runtest_makereport)


前言

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 后置操作")

運行結果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM