setup/teardown using conftest in pytest
Asked Answered
B

3

11

I have different test folders(packages). I want to setup and teardown some data for a specific package(folder).

The problem is set_up() is executed before running the test cases of that folder but after running all the testcases, tear_down is not executing. It's executing after running all the testcases of other packages (folders) also(after whole session of pytest).

     [conftest.py]

     @pytest.fixture(scope="session", autouse=True)
         def set_up(request):
            '''Test package setup'''

         def tear_down():
            '''Test package teardown'''

Each folder contains __init__.py file which is obvious.

So how do i execute the tear_down() just after running all the testcases in that folder for which set_up is executed?

as far i know: scope="module" is useless in this case as i dont want to setup and teardown for each test.

Any help would be great. Thanks

Bohr answered 2/4, 2014 at 10:16 Comment(2)
What kind of data are you setting up and tearing down? As I understand your question, you want something like a fixture with a scope of "package", where you can specify the package. Is that correct?Caster
Yes package fixture. Data is basically related to inserting some values in cassandra database befor i start the test and after all the tests in that folder are finished i want to truncate all the tables.Bohr
D
10

pytest does not directly support package level fixtures. Neither does unittest.

As for the main test frameworks, I believe nose is the only one to support package fixtures. However, nose2 is dropping package fixture support. See nose2 docs.

pytest supports module, function, class, and method level fixtures for xunit style fixtures.

Deucalion answered 7/4, 2014 at 16:39 Comment(1)
using nose is not a good idea then.I knew this but i raised this question in-case if i missed something.There is no good solution but Thanks anyway.Bohr
G
7

conftest.py files are directory-level (read "package") configurations. So if you put one at the root directory of your tests, its session-scoped fixtures will run at the beginning of that scope and the corresponding tear_down will wait for the scope's conclusion (i.e. the entire test session) before executing. If you need to create fixtures that span only sub-directories (sub-packages), you need to put additional conftest.py files at those levels (with their own scope='session' fixtures). A common example is to add data to a database. Imagine wanting to populate your purchases db table with some rows for all your tests inside the corresponding test package. You'd place the fixture that does the job inside tests.purchases.conftest.py.

shopping_app/
tests/
    __init__.py
    conftest.py # applies to all tests
    buyers/
    products/
    purchases/
        conftest.py # only applies to this scope and sub-scopes
        __init__.py
        test1.py
        test2.py
        payments/
        refunds/
    sellers/
    stores/

And inside tests.purchases.conftest.py you'd have ordinary fixture declarations. For instance a set_up/tear_down combo to prepopulate and delete rows for your db table would looks something like this:

@pytest.fixture(scope='session', autouse=True)
def prep_purchases(db, data):
    # set_up: fill table at beginning of scope
    populate_purchase_table_with_data(db, data)

    # yield, to let all tests within the scope run
    yield 

    # tear_down: then clear table at the end of the scope
    empty_purchase_table(db)

Some fixtures do not need to be explicitly injected into tests (we're only interested by their side-effect, not their return value), hence the autouse parameter. As for the context manager syntax for set_up/tear_down (with yield), if you're not comfortable with it, you can alternatively place the tear_down part as its own separate function.

Ginoginsberg answered 2/4, 2020 at 14:10 Comment(2)
Whether or not this answer is relevant to OP's question it deserves upvotes as an excellent approach to tearing down (in my case removing files created by the tests) after all the tests have run. I've looked at a bunch of other alternatives and most were really kludgy.Kneepan
@Kneepan I forgot about this answer. I think it needs editing as I believe that pytest has changed its approach a bit. There's now a (experimental) "package" scope that is better suited. The "session" scope now fully belongs to the testing session as a whole. I should edit (or delete) the answer accordingly.Ginoginsberg
O
0

I was looking for something different, namely that any kind of code could be run after all the tests are run, (so not just variables called by the other tests).

The solution was quite simple. In conftest.py add a pytest_sessionfinish function.


import pytest 

def pytest_sessionfinish(session, exitstatus):
    """
    Hook to run after all tests have completed.
    :param session: The pytest session object
    :param exitstatus: The status of the pytest run
    """
    # Your code here
    print("All tests have finished!")
    delete_files()
    shutdown_cloud_testing_resources()
Ongun answered 10/7, 2024 at 12:22 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.