nevadakid
nevadakid

Reputation: 31

How do I run a fixture only when the test fails?

I have the following example:

conftest.py:

@pytest.fixture:
def my_fixture_1(main_device)
  yield
  if FAILED:
    -- code lines --
  else:
    pass

main.py:

def my_test(my_fixture_1):
  main_device = ...
  -- code lines --
  assert 0

  -- code lines --
  assert 1

When assert 0, for example, the test should fail and execute my_fixture_1. If the test pass, the fixture must not execute. I tried using hookimpl but didn't found a solution, the fixture is always executing even if the test pass.

Note that main_device is the device connected where my test is running.

Upvotes: 3

Views: 4613

Answers (2)

Nantha gopal
Nantha gopal

Reputation: 49

In Simon Hawe's answer, request.session.testsfailed denotes the number of test failures in that particular test run.

Here is an alternative solution that I can think of.

import os


@pytest.fixture(scope="module")
def main_device():
    return None


@pytest.fixture(scope='function', autouse=True)
def my_fixture_1(main_device):
    yield
    if os.environ["test_result"] == "failed":
        print("+++++++++ Test Failed ++++++++")
    elif os.environ["test_result"] == "passed":
        print("+++++++++ Test Passed ++++++++")
    elif os.environ["test_result"] == "skipped":
        print("+++++++++ Test Skipped ++++++++")


def pytest_runtest_logreport(report):
    if report.when == 'call':
        os.environ["test_result"] = report.outcome

You can do your implementations directly in the pytest_runtest_logreport hook itself. But the drawback is that you won't get access to the fixtures other than the report.

So, if you need main_device, you have to go with a custom fixture like as shown above.

Use @pytest.fixture(scope='function', autouse=True) which will automatically run it for every test case. you don't have to give main_device in all test functions as an argument.

Upvotes: 2

Simon Hawe
Simon Hawe

Reputation: 4529

You could use request as an argument to your fixture. From that, you can check the status of the corresponding tests, i.e. if it has failed or not. In case it failed, you can execute the code you want to get executed on failure. In code that reads as

@pytest.fixture
def my_fixture_1(request):
  yield
  if request.session.testsfailed:
    print("Only print if failed")

Of course, the fixture will always run but the branch will only be executed if the corresponding test failed.

Upvotes: 1

Related Questions