Skip to content

Session scoped fixture run multiple times when adding fixture via metafunc #5738

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Drau opened this issue Aug 14, 2019 · 5 comments
Closed
Labels
topic: fixtures anything involving fixtures directly or indirectly topic: parametrize related to @pytest.mark.parametrize

Comments

@Drau
Copy link

Drau commented Aug 14, 2019

pytest v5.0.1

(All code can be found here: example repo)

When defining a session scoped fixture inside pytest_generate_tests hook,
while also using metafunc.parametrize to make all tests repeat N times,
Every fixture that uses the newly created job_id fixture, is called N times (Once before every test iteration)

conftest.py

import pytest

def pytest_generate_tests(metafunc):
      # Make all tests repeat 4 times
      metafunc.fixturenames.append('repeat')
      metafunc.parametrize('repeat', range(1,5))
      # Create a new session scoped fixture
      metafunc.parametrize("job_id", [100], scope='session')

@pytest.fixture(scope='session', autouse=True)
def fix1(job_id):
    print('IN session scope'

test_1.py

import pytest

def test_1():
    assert True

def test_2():
    assert True

Result: fix1 fixture is called, then the 2 tests are called, then again fix1 and so on...

python -m pytest -s
=== test session starts ===
platform darwin -- Python 3.7.3, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
rootdir: /Users/michaelr/tmp/issue
collected 8 items

test_1.py IN session scope
..IN session scope
..IN session scope
..IN session scope
..

=== 8 passed in 0.03 seconds ===

I would expect that all session scoped fixtures will run only once.

@Drau
Copy link
Author

Drau commented Aug 14, 2019

OK so Ive managed to find a workaround but I have no idea if thats the correct way or an ugly hack!

By adding indirect=True to metafunc.parametrize("job_id", [100], scope='session')

metafunc.parametrize("job_id", [100], scope='session', indirect=True)

and creating a new fixture:

@pytest.fixture(scope='session')
def job_id(request):
    return request.param

The issue was fixed:

python -m pytest -s
=== test session starts ===
platform darwin -- Python 3.7.3, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
rootdir: /Users/michaelr/tmp/issue
collected 8 items

test_1.py IN session scope
........

=== 8 passed in 0.02 seconds ===

Only thing is that now, instead of the order:
test1-iteration1
test2-iteration1
test1-iteration2
test2-iteration2
test1-iteration3
test2-iteration3
test1-iteration4
test2-iteration4

The order is:

test1-iteration1
test1-iteration2
test1-iteration3
test1-iteration4
test2-iteration1
test2-iteration2
test2-iteration3
test2-iteration4

Which is kinda weird but..oh well..
Ill be happy to learn why this works. if this is in fact the correct way to handle the issue in the opening comment.

Thanks.

@RonnyPfannschmidt
Copy link
Member

Good find, this narrows the issue down a bit

@Zac-HD Zac-HD added topic: fixtures anything involving fixtures directly or indirectly topic: parametrize related to @pytest.mark.parametrize labels Aug 16, 2019
@Zac-HD
Copy link
Member

Zac-HD commented Aug 16, 2019

Thanks for the report @Drau!

Not sure how to help with your issue, but FYI you can enable syntax highlighting for code blocks on GitHub which makes them a bit easier to read 😄

@aklajnert
Copy link
Contributor

I think this issue can be closed. Tested on pytest 5.4 and 6.0, both behave as expected:

platform linux -- Python 3.8.2, pytest-6.0.1.dev55+g701998bf2, py-1.9.0, pluggy-0.13.1 -- /tmp/pytest-master/bin/python3
cachedir: .pytest_cache
rootdir: /mnt/c/Users/aklajnert/PycharmProjects/pytest, configfile: pyproject.toml
collected 8 items

test_1.py::test_1[1-100] IN session scope: 100
PASSED
test_1.py::test_2[1-100] PASSED
test_1.py::test_1[2-100] PASSED
test_1.py::test_2[2-100] PASSED
test_1.py::test_1[3-100] PASSED
test_1.py::test_2[3-100] PASSED
test_1.py::test_1[4-100] PASSED
test_1.py::test_2[4-100] PASSED

@grtdeveloper
Copy link

OK so Ive managed to find a workaround but I have no idea if thats the correct way or an ugly hack!

By adding indirect=True to metafunc.parametrize("job_id", [100], scope='session')

metafunc.parametrize("job_id", [100], scope='session', indirect=True)

and creating a new fixture:

@pytest.fixture(scope='session')
def job_id(request):
    return request.param

The issue was fixed:

python -m pytest -s
=== test session starts ===
platform darwin -- Python 3.7.3, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
rootdir: /Users/michaelr/tmp/issue
collected 8 items

test_1.py IN session scope
........

=== 8 passed in 0.02 seconds ===

Only thing is that now, instead of the order: test1-iteration1 test2-iteration1 test1-iteration2 test2-iteration2 test1-iteration3 test2-iteration3 test1-iteration4 test2-iteration4

The order is:

test1-iteration1 test1-iteration2 test1-iteration3 test1-iteration4 test2-iteration1 test2-iteration2 test2-iteration3 test2-iteration4

Which is kinda weird but..oh well.. Ill be happy to learn why this works. if this is in fact the correct way to handle the issue in the opening comment.

Thanks.

Hi Drau: can u tell me how r u able to achieve this in detail. M also trying to achieve the same. Any help is much appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: fixtures anything involving fixtures directly or indirectly topic: parametrize related to @pytest.mark.parametrize
Projects
None yet
Development

No branches or pull requests

5 participants