Skip to content
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

fixture scope is ignored when using metafunc.parametrize() #519

Closed
pytestbot opened this issue May 27, 2014 · 5 comments
Closed

fixture scope is ignored when using metafunc.parametrize() #519

pytestbot opened this issue May 27, 2014 · 5 comments
Labels
topic: fixtures anything involving fixtures directly or indirectly topic: parametrize related to @pytest.mark.parametrize type: bug problem that needs to be addressed

Comments

@pytestbot
Copy link
Contributor

pytestbot commented May 27, 2014

Originally reported by: Nikolaus Rath (BitBucket: nikratio, GitHub: nikratio)


Please take a look at the following example:

import pytest

def pytest_generate_tests(metafunc):
    if 'arg1' in metafunc.fixturenames:
        metafunc.parametrize("arg1", [ 'arg1v1', 'arg1v2' ], scope='module')

    if 'arg2' in metafunc.fixturenames:
        metafunc.parametrize("arg2", [ 'arg2v1', 'arg2v2' ], scope='function')

@pytest.yield_fixture(scope='module')
def fix1(arg1):
    print('running fix1 with', arg1)
    yield 'fix1-' + arg1

@pytest.yield_fixture(scope='function')
def fix2(fix1, arg2):
    print('running fix2 with', fix1, arg2)
    yield 'fix2-' + arg2 + fix1

def test_one(fix2):
    assert True

def test_two(fix2):
    assert True

As I understand, test_one and test_two should be executed 4 times each. The fix2 function should be called once for every test execution (because it has function scope), and the fix1 function once for every value of arg1 (because it has module scope).

However, in practice fix1 seems to be called for every test function as well, as if it had function scope:

$ python3 ~/clones/pytest/pytest.py -v -s test_bug.py
============================= test session starts ==============================
platform linux -- Python 3.3.5 -- py-1.4.20 -- pytest-2.6.0.dev1 -- /usr/bin/python3
collected 8 items 

test_bug.py@20::test_one[arg1v1-arg2v1] running fix1 with arg1v1
running fix2 with fix1-arg1v1 arg2v1
PASSED
test_bug.py@23::test_two[arg1v1-arg2v1] running fix2 with fix1-arg1v1 arg2v1
PASSED
test_bug.py@20::test_one[arg1v1-arg2v2] running fix1 with arg1v1
running fix2 with fix1-arg1v1 arg2v2
PASSED
test_bug.py@23::test_two[arg1v1-arg2v2] running fix2 with fix1-arg1v1 arg2v2
PASSED
test_bug.py@20::test_one[arg1v2-arg2v1] running fix1 with arg1v2
running fix2 with fix1-arg1v2 arg2v1
PASSED
test_bug.py@23::test_two[arg1v2-arg2v1] running fix2 with fix1-arg1v2 arg2v1
PASSED
test_bug.py@20::test_one[arg1v2-arg2v2] running fix1 with arg1v2
running fix2 with fix1-arg1v2 arg2v2
PASSED
test_bug.py@23::test_two[arg1v2-arg2v2] running fix2 with fix1-arg1v2 arg2v2
PASSED

=========================== 8 passed in 0.01 seconds ===========================

Looks like a bug to me.

@pytestbot pytestbot added the type: bug problem that needs to be addressed label Jun 15, 2015
@pfctdayelise pfctdayelise added the topic: parametrize related to @pytest.mark.parametrize label Jul 25, 2015
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest that referenced this issue Jan 18, 2017
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest that referenced this issue Jan 18, 2017
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest that referenced this issue Jul 28, 2017
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest that referenced this issue Jul 28, 2017
@ceridwen
Copy link
Contributor

I have a test suite where I have to run some very expensive configuration before running all the tests, and the set of possible configurations is the Cartesian product of modes that are fixed with versions that I need to be able to pass in at run-time. I'm currently using a session-scoped fixture that's parametrized only by the modes, and I need to extend it to be parametrized by the versions too. The only way I've found to do parametrization of a fixture dependent on command-line arguments is pytest_generate_tests, but this bug breaks it for session fixtures. Thus, I see three possible routes:

  1. Fix this bug. I'm guessing, though, that it would be hard to impossible. Where is the code that's responsible for handling fixture scoping? Does anyone know the cause of this bug?
  2. Work around it somehow. I don't know to how to do this. Someone on IRC suggested adding pytest.mark.parametrize('session_fixture', params, indirect=True, scope='session') to a test, but for this test suite there's no one test that will always be run, and I don't understand exactly how this is supposed to work. Are there any other workarounds for this bug?
  3. Move the session-level configuration out of pytest, which has its own disadvantages.

@nicoddemus
Copy link
Member

@ceridwen I think the proper way to define fixtures dynamically based on command-line variables is demonstrated in #2959 (comment). Does that solve it for you?

@ceridwen
Copy link
Contributor

Unfortunately, not quite, see #3161. I'm starting to suspect there's a more fundamental bug lurking here.

RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest that referenced this issue Jun 15, 2018
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest that referenced this issue Jun 15, 2018
nicoddemus added a commit that referenced this issue Jun 15, 2018
@Zac-HD Zac-HD added the topic: fixtures anything involving fixtures directly or indirectly label Oct 21, 2018
blueyed added a commit to blueyed/pytest that referenced this issue Feb 24, 2020
Note that the output changed with 9e26203, so the test should likely
be fixed.

Ref: pytest-dev#519 (- haven't looked into what the issue is about).

Example script was added in c081c5e, changed in ea90605, currently outputs:

Previous output:
```
['============================= test session starts ==============================',
 'platform linux -- Python 3.8.1, pytest-5.3.5.dev567+gfba7d992a.d20200224, py-1.8.2.dev3+g2b6bd292, pluggy-0.13.1',
 'rootdir: ~',
 'collected 8 items',
 '',
 'issue_519.py ........E                                                   [100%]',
 '',
 '==================================== ERRORS ====================================',
 '_________________ ERROR at teardown of test_two[arg1v2-arg2v2] _________________',
 '',
 '    @pytest.fixture(scope="session")',
 '    def checked_order():',
 '        order = []',
 '    ',
 '        yield order',
 '        pprint.pprint(order)',
 '>       assert order == [',
 '            ("testing/example_scripts/issue_519.py", "fix1", "arg1v1"),',
 '            ("test_one[arg1v1-arg2v1]", "fix2", "arg2v1"),',
 '            ("test_two[arg1v1-arg2v1]", "fix2", "arg2v1"),',
 '            ("test_one[arg1v1-arg2v2]", "fix2", "arg2v2"),',
 '            ("test_two[arg1v1-arg2v2]", "fix2", "arg2v2"),',
 '            ("testing/example_scripts/issue_519.py", "fix1", "arg1v2"),',
 '            ("test_one[arg1v2-arg2v1]", "fix2", "arg2v1"),',
 '            ("test_two[arg1v2-arg2v1]", "fix2", "arg2v1"),',
 '            ("test_one[arg1v2-arg2v2]", "fix2", "arg2v2"),',
 '            ("test_two[arg1v2-arg2v2]", "fix2", "arg2v2"),',
 '        ]',
 "E       AssertionError: assert [('issue_519....arg1v2'), ...] == [('testing/ex...arg1v2'), ...]",
 'E         At index 0 diff:',
 "E         ('issue_519.py', 'fix1', 'arg1v1') !=",
 "E         ('testing/example_scripts/issue_519.py', 'fix1', 'arg1v1')",
 'E         Use -v to get the full diff',
 '',
 "issue_519.py:20: AssertionError: assert [('issue_519....arg1v2'), ...] == [('testing/ex...arg1v2'), ...]...",
 '--------------------------- Captured stdout teardown ---------------------------',
 "[('issue_519.py', 'fix1', 'arg1v1'),",
 " ('test_one[arg1v1-arg2v1]', 'fix2', 'arg2v1'),",
 " ('test_two[arg1v1-arg2v1]', 'fix2', 'arg2v1'),",
 " ('test_one[arg1v1-arg2v2]', 'fix2', 'arg2v2'),",
 " ('test_two[arg1v1-arg2v2]', 'fix2', 'arg2v2'),",
 " ('issue_519.py', 'fix1', 'arg1v2'),",
 " ('test_one[arg1v2-arg2v1]', 'fix2', 'arg2v1'),",
 " ('test_two[arg1v2-arg2v1]', 'fix2', 'arg2v1'),",
 " ('test_one[arg1v2-arg2v2]', 'fix2', 'arg2v2'),",
 " ('test_two[arg1v2-arg2v2]', 'fix2', 'arg2v2')]",
```
@RonnyPfannschmidt
Copy link
Member

i believe #11220 fixed this one

@nicoddemus
Copy link
Member

Thanks @RonnyPfannschmidt, let's close this then, and reopen if we find it was not the case. 👍

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 type: bug problem that needs to be addressed
Projects
None yet
Development

No branches or pull requests

6 participants