2

right now I'm trying to convert some API tests from Nose to Pytest. When I tried to do that I faced a little problem: Pytest doesnt support the "setup_package()" functionality. The "setup_package()" is in the __init__.py file of where the tests are.

This is the directory structure:

tests/__init__.py
      test_001.py
      test_002.py
      ...

A easy solution would be to give the setup_package() function a fixture, but the problem here is, that my setup_package() is accessing a global counter in the __init__.py. So that the __ini__.py file looks like that:

counter_id = 0

def setup_package():
    global counter
    counter = some_function()

def teardown_package():
    global counter
    clear_object(counter_id)

Im pretty sure, that there is very easy solution to migrate this but as I'm new to Pytest I want to know the "pytestian" way of migrating this particular example to Pytest! My first idea was to use a fixture with params functionality, but I'm not sure if it's a good way to migrate at all.

Faram
  • 525
  • 6
  • 21
  • An [autouse fixture](https://docs.pytest.org/en/latest/fixture.html#autouse-fixtures-xunit-setup-on-steroids) with a [session scope](https://docs.pytest.org/en/latest/fixture.html#scope-sharing-a-fixture-instance-across-tests-in-a-class-module-or-session) covers the use case of `setup_package`/`teardown_package`. If you need a recipe for having global variables in `pytest`, [this question](https://stackoverflow.com/questions/22768976) should help. – hoefling Sep 17 '18 at 10:29
  • I tried to do: @fixture(autouse=True, scope="package") at setup_package and teardown_package but it's not firing. Why did I do wrong? – Faram Sep 17 '18 at 11:50
  • `@pytest(scope='session', autouse=True) def my_setup_func(): counter = some_function(); yield; clear_object(counter)` replaces both `setup_package` and `teardown_package` in one fixture. – hoefling Sep 17 '18 at 12:32
  • 1
    I did that already. Thanks. I got it worked when I created a conftest.py file and copied it there. – Faram Sep 17 '18 at 12:46
  • You're right - this should be packed into a `conftest` file to work project-wide, my bad! – hoefling Sep 17 '18 at 12:50
  • Please feel free to answer this question, as your answer was the correct solution (even though you didn't mention the conftest file, but that was just a minor detail). Again: Thank you very much :) – Faram Sep 18 '18 at 08:09
  • @TheOnionMaster would you mind to post what you did to solve the issue as response for this question? I am facing the same problem but I had no success with conftest. Might be doing something wrong form my side, so you answer could help I think. – lucrib Feb 19 '19 at 14:36
  • 1
    @lucrib Have a look at my solution :) – Faram Feb 21 '19 at 13:47

1 Answers1

2

As @hoefling already hinted in the comments:

I just created a new conftest.py (relate to In pytest, what is the use of conftest.py files?) file in the tests directory (see initial question for the folder structure).

tests/__init__.py
      conftest.py
      test_001.py
      test_002.py
      ... 

In that conftest.py file, I just copied the setup_package function in it, with the following fixture:

@pytest.fixture(scope='session', autouse=True)
def setup_and_teardown_package():
(...) #setup
yield
(...) #teardown

Regarding the counter_id: We don't need flags anymore, as we have a single function for our setup and teardown, so that the variables wont be lost. The yield tells the function to stop, till all the tests are done, and then to continue with the the method. So basically: Everything BEFORE yield will behave like the setup and everything AFTER the yield will behave like the teardown -> There is no need for globals anymore :)

Faram
  • 525
  • 6
  • 21