Run code before and after each test in py.test? Run code before and after each test in py.test? python python

Run code before and after each test in py.test?


py.test fixtures are a technically adequate method to achieve your purpose.

You just need to define a fixture like that:

@pytest.fixture(autouse=True)def run_around_tests():    # Code that will run before your test, for example:    files_before = # ... do something to check the existing files    # A test function will be run at this point    yield    # Code that will run after your test, for example:    files_after = # ... do something to check the existing files    assert files_before == files_after

By declaring your fixture with autouse=True, it will be automatically invoked for each test function defined in the same module.

That said, there is one caveat. Asserting at setup/teardown is a controversial practice. I'm under the impression that the py.test main authors do not like it (I do not like it either, so that may colour my own perception), so you might run into some problems or rough edges as you go forward.


You can use a fixture in oder to achieve what you want.

import pytest@pytest.fixture(autouse=True)def run_before_and_after_tests(tmpdir):    """Fixture to execute asserts before and after a test is run"""    # Setup: fill with any logic you want    yield # this is where the testing happens    # Teardown : fill with any logic you want

Detailed Explanation

  1. @pytest.fixture(autouse=True), from the docs: "Occasionally, you may want to have fixtures get invoked automatically without declaring a function argument explicitly or a usefixtures decorator." Therefore, this fixture will run every time a test is executed.

  2. # Setup: fill with any logic you want, this logic will be executed before every test is actually run. In your case, you can add your assert statements that will be executed before the actual test.

  3. yield, as indicated in the comment, this is where testing happens

  4. # Teardown : fill with any logic you want, this logic will be executed after every test. This logic is guaranteed to run regardless of what happens during thetests.

Note: in pytest there is a difference between a failing test and an error while executing a test. A Failure indicates that the test failed in some way.An Error indicates that you couldn't get to the point of doing a proper test.

Consider the following examples:

Assert fails before test is run -> ERROR

import pytest@pytest.fixture(autouse=True)def run_around_tests():    assert False # This will generate an error when running tests    yield    assert Truedef test():    assert True

Assert fails after test is run -> ERROR

import pytest@pytest.fixture(autouse=True)def run_around_tests():    assert True    yield    assert Falsedef test():    assert True

Test fails -> FAILED

import pytest@pytest.fixture(autouse=True)def run_around_tests():    assert True    yield    assert Truedef test():    assert Fail

Test passes -> PASSED

import pytest@pytest.fixture(autouse=True)def run_around_tests():    assert True    yield    assert Truedef test():    assert True


Fixtures are exactly what you want. That's what they are designed for.

Whether you use pytest style fixtures, or setup and teardown (module, class, or method level) xUnit style fixtures, depends on the circumstance and personal taste.

From what you are describing, it seems like you could use pytest autouse fixtures.
Or xUnit style function level setup_function()/teardown_function().

Pytest has you completely covered. So much so that perhaps it's a fire hose of information.