如何仅在测试错误或失败时运行 pytest 夹具清理

问题描述 投票:0回答:2

我想仅在测试不成功时保存

pytest
测试运行的日志文件,这可能是由于测试装置设置中的错误或测试本身的失败造成的。

我的方法是创建一个测试装置,复制

yield
之后的日志,但我不知道如何使其以测试结果为条件。

@pytest.fixture
def setup():
    do_setup()
    yield
    do_teardown()

@pytest.fixture
def get_logs():
    yield
    if not test_success: # how to know this condition?
        copy_log_files()

def test_run(get_logs, setup):
    do_test_stuff()
python pytest
2个回答
3
投票

使用pytest_runtest_makereport,如文档所示:

调用为测试项的每个设置、调用和拆卸运行测试阶段创建 _pytest.reports.TestReport。

并将其与 _Result.get_result() 一起使用以将结果添加到 Node/Item中。

我们实际上可以按照在夹具中提供测试结果信息

中记录的相同步骤进行操作

conftest.py

import pytest


@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    # execute all other hooks to obtain the report object
    outcome = yield
    rep = outcome.get_result()

    # set a report attribute for each phase of a call, which can
    # be "setup", "call", "teardown"

    setattr(item, "rep_" + rep.when, rep)

test_module.py

import pytest


@pytest.fixture
def get_logs(request):
    yield

    if request.node.rep_call.failed:
        # Add code here to cleanup failure scenario
        print("executing test failed")
    elif request.node.rep_call.passed:
        # Add code here to cleanup success scenario
        print("executing test success")


def test_run1(get_logs):
    print("Test 1")
    assert 1


def test_run2(get_logs):
    print("Test 2")
    assert 0


def test_run3(get_logs):
    print("Test 3")
    assert 1


def test_run4(get_logs):
    print("Test 4")
    assert 0

输出

$ pytest -rP test_module.py
test_module.py .F.F                                                                           [100%]

============================================= FAILURES ==============================================
_____________________________________________ test_run2 _____________________________________________

get_logs = None

    def test_run2(get_logs):
        print("Test 2")
>       assert 0
E       assert 0

test_module.py:21: AssertionError
--------------------------------------- Captured stdout call ----------------------------------------
Test 2
------------------------------------- Captured stdout teardown --------------------------------------
executing test failed
_____________________________________________ test_run4 _____________________________________________

get_logs = None

    def test_run4(get_logs):
        print("Test 4")
>       assert 0
E       assert 0

test_module.py:31: AssertionError
--------------------------------------- Captured stdout call ----------------------------------------
Test 4
------------------------------------- Captured stdout teardown --------------------------------------
executing test failed
============================================== PASSES ===============================================
_____________________________________________ test_run1 _____________________________________________
--------------------------------------- Captured stdout call ----------------------------------------
Test 1
------------------------------------- Captured stdout teardown --------------------------------------
executing test success
_____________________________________________ test_run3 _____________________________________________
--------------------------------------- Captured stdout call ----------------------------------------
Test 3
------------------------------------- Captured stdout teardown --------------------------------------
executing test success
==================================== 2 failed, 2 passed in 0.11s ====================================

0
投票

与上一个答案相比,语法似乎发生了一些变化。这是对我有用的方法,并添加了一些额外的内容来展示如何设置每次测试的清理:

# conftest.py

@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
    # execute all other hooks to obtain the report object
    outcome = yield

    setattr(item, "rep_" + outcome.get_result().when + '_passed', outcome.get_result().passed)

class Cleanups(object):
    def set_success(this, success_cleanup: Callable[[], None]):
        this.success_cleanup = success_cleanup
    
    def set_failure(this, failure_cleanup: Callable[[], None]):
        this.failure_cleanup = failure_cleanup

@pytest.fixture
def cleanups(request):
    cleanups = Cleanups()
    yield cleanups

    if request.node.rep_call_passed:
        cleanup = cleanups.success_cleanup
    else:
        cleanup = cleanups.failure_cleanup
    if cleanup:
        cleanup()

# -----
# test.py

def test_that_passes(cleanups):
  thing = create_thing()
  assert thing.is_good()

  def success_cleanup():
    thing.destroy()
  cleanups.set_success(success_cleanup)

  def failure_cleanup():
    print('Uh oh, the thing was bad!')
  cleanups.set_failure(failure_cleanup)
© www.soinside.com 2019 - 2024. All rights reserved.