0

I want to use indirect parametrization as shown in this answer and in pytest documentation.

I want to be able to set scope to be able to configure if fixture is run for every function or once for many of them.

However I see that I can set scope on fixture decorator:

import pytest

@pytest.fixture(scope="function")
def fixt(request):
    return request.param * 3

@pytest.mark.parametrize("fixt", ["a", "b"], indirect=True)
def test_indirect(fixt):
    assert len(fixt) == 3

Or on parametrize decorator:

import pytest

@pytest.fixture
def fixt(request):
    return request.param * 3

@pytest.mark.parametrize("fixt", ["a", "b"], indirect=True, scope="function")
def test_indirect(fixt):
    assert len(fixt) == 3

Or even both at the same time:

import pytest

@pytest.fixture(scope="function")
def fixt(request):
    return request.param * 3

@pytest.mark.parametrize("fixt", ["a", "b"], indirect=True, scope="function")
def test_indirect(fixt):
    assert len(fixt) == 3

What is the difference and when I should set each?


Update:

I tested each to see how they differ.

Code I used for testing:

import pytest

scope_fixture="function"
scope_parametrize="module"

with open('scope_log.txt', 'a') as file:
    file.write(f'--------\n')
    file.write(f'{scope_fixture=}\n')
    file.write(f'{scope_parametrize=}\n')

@pytest.fixture(scope=scope_fixture)
def fixt(request):
    with open('scope_log.txt', 'a') as file:
        file.write(f'fixture ' + str(request.param)+'\n')
    return request.param * 3

@pytest.mark.parametrize("fixt", ["a", "b"], indirect=True, scope=scope_parametrize)
def test_indirect1(fixt):
    with open('scope_log.txt', 'a') as file:
        file.write(f'1 ' + str(fixt)+'\n')
    assert len(fixt) == 3

@pytest.mark.parametrize("fixt", ["a", "b"], indirect=True, scope=scope_parametrize)
def test_indirect2(fixt):
    with open('scope_log.txt', 'a') as file:
        file.write(f'2 ' + str(fixt)+'\n')
    assert len(fixt) == 3

Results:

scope_fixture=None
scope_parametrize=None
fixture a
1 aaa
fixture b
1 bbb
fixture a
2 aaa
fixture b
2 bbb
--------
scope_fixture='function'
scope_parametrize=None
fixture a
1 aaa
fixture b
1 bbb
fixture a
2 aaa
fixture b
2 bbb
--------
scope_fixture='module'
scope_parametrize=None
fixture a
1 aaa
2 aaa
fixture b
1 bbb
2 bbb
--------
scope_fixture=None
scope_parametrize='function'
fixture a
1 aaa
fixture b
1 bbb
fixture a
2 aaa
fixture b
2 bbb
--------
scope_fixture=None
scope_parametrize='module'
fixture a
1 aaa
2 aaa
fixture b
1 bbb
2 bbb
--------
scope_fixture='function'
scope_parametrize='module'
fixture a
1 aaa
2 aaa
fixture b
1 bbb
2 bbb
--------
scope_fixture='module'
scope_parametrize='module'
fixture a
1 aaa
2 aaa
fixture b
1 bbb
2 bbb
--------
scope_fixture='module'
scope_parametrize='function'
fixture a
1 aaa
fixture b
1 bbb
fixture a
2 aaa
fixture b
2 bbb
--------
scope_fixture='function'
scope_parametrize='function'
fixture a
1 aaa
fixture b
1 bbb
fixture a
2 aaa
fixture b
2 bbb

Karol Zlot
  • 2,887
  • 2
  • 20
  • 37
  • Did you try using each? Could you observe a difference in what tests occurred (or, for that matter, how many)? – Karl Knechtel Jan 21 '22 at 13:25
  • 1
    Setting the scope for `parametrize´ [overrides any scope set in fixtures.](https://docs.pytest.org/en/latest/reference/reference.html#pytest.Metafunc.parametrize) I would only set the scope if I have to, one example could be the case of reading input from a file and I only want to do it once to save time with I/O. – Tzane Jan 21 '22 at 14:06

1 Answers1

0

As @Tzane pointed out in comment, setting the scope for parametrize overrides any scope set in fixtures.

From documentation:

scope (Optional[_ScopeName]) – If specified it denotes the scope of the parameters. The scope is used for grouping tests by parameter instances. It will also override any fixture-function defined scope, allowing to set a dynamic scope using test context or configuration.

Karol Zlot
  • 2,887
  • 2
  • 20
  • 37