Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use a parametrized dependent fixture twice in pytest?

I'm trying to use a parametrized fixture multiple times in a single test, with the intent of getting a cartesian product of all of its values.

https://stackoverflow.com/a/39444098/102441 shows how to do this for a simple fixture:

import pytest

@pytest.fixture(params=[0, 1, 2])
def first(request):
    return request.param

second = first

# runs 3x3 = 9 times
def test_double_fixture(first, second):
    assert False, '{} {}'.format(first, second)

However, this approach falls apart if the parametrization comes from a dependent fixture:

import pytest

@pytest.fixture(params=[0, 1, 2])
def integer(request):
    return request.param

@pytest.fixture
def squared_integer(integer):
    return integer * integer

@pytest.fixture
def first(squared_integer):
    return squared_integer

second = first

# runs only 3 times
def test_double_fixture(first, second):
    assert False, '{} {}'.format(first, second)

How can I make this run 3x3 tests like the simple example does?

like image 396
Eric Avatar asked Jan 04 '19 18:01

Eric


People also ask

How many times will a fixture of module scope run?

Module: If the Module scope is defined, the fixture will be created/invoked only once per module. Class: With Class scope, one fixture will be created per class object. Session: With the Session scope, the fixture will be created only once for entire test session.

Can a pytest fixture use another fixture?

A fixture can use multiple other fixtures. Just like a test method can take multiple fixtures as arguments, a fixture can take multiple other fixtures as arguments and use them to create the fixture value that it returns.

How often is a fixture function in pytest executed?

Fixtures with scope session will only be executed once per session. Every time you run pytest , it's considered to be one session.

Which fixture is instantiated second?

m1 : is the second highest-scoped fixture ( module ). tmpdir : is a function -scoped fixture, required by f1 : it needs to be instantiated at this point because it is a dependency of f1 .


1 Answers

This is correct behavior of pytest. Because you use integer deep inside other fixtures. To understand what happens check pytest with --setup-show flag. You will see something like:

        SETUP    F integer[0]
        SETUP    F squared_integer (fixtures used: integer)
        SETUP    F first (fixtures used: squared_integer)
        SETUP    F second (fixtures used: squared_integer)
        Test/test_54044536_3.py::test_double_fixture[0] (fixtures used: first, integer, second, squared_integer)F
        TEARDOWN F second
        TEARDOWN F first
        TEARDOWN F squared_integer
        TEARDOWN F integer[0]

So integer values only for squared_integer function.

To answer you question, we can refactor your code to fixtures and one function. This will look like:

import pytest

def squared_integer(integer):
    return integer * integer


@pytest.fixture(params=[0, 1, 2])
def first(request):
    return squared_integer(request.param)

second = first

# runs only 3 times
def test_double_fixture(first, second):
    assert False, '{} {}'.format(first, second)

And you will have 9 tests with such sequence:

        SETUP    F first[0]
        SETUP    F second[0]
        Test/test_54044536_2.py::test_double_fixture[0-0] (fixtures used: first, second)F
        TEARDOWN F second[0]
        TEARDOWN F first[0]
        SETUP    F first[0]
        SETUP    F second[1]
        Test/test_54044536_2.py::test_double_fixture[0-1] (fixtures used: first, second)F
        TEARDOWN F second[1]
        TEARDOWN F first[0]
        SETUP    F first[0]
        SETUP    F second[2]
        Test/test_54044536_2.py::test_double_fixture[0-2] (fixtures used: first, second)F
        TEARDOWN F second[2]
        TEARDOWN F first[0]
        SETUP    F first[1]
        SETUP    F second[0]
        Test/test_54044536_2.py::test_double_fixture[1-0] (fixtures used: first, second)F
        TEARDOWN F second[0]
        TEARDOWN F first[1]
        SETUP    F first[1]
        SETUP    F second[1]
        Test/test_54044536_2.py::test_double_fixture[1-1] (fixtures used: first, second)F
        TEARDOWN F second[1]
        TEARDOWN F first[1]
        SETUP    F first[1]
        SETUP    F second[2]
        Test/test_54044536_2.py::test_double_fixture[1-2] (fixtures used: first, second)F
        TEARDOWN F second[2]
        TEARDOWN F first[1]
        SETUP    F first[2]
        SETUP    F second[0]
        Test/test_54044536_2.py::test_double_fixture[2-0] (fixtures used: first, second)F
        TEARDOWN F second[0]
        TEARDOWN F first[2]
        SETUP    F first[2]
        SETUP    F second[1]
        Test/test_54044536_2.py::test_double_fixture[2-1] (fixtures used: first, second)F
        TEARDOWN F second[1]
        TEARDOWN F first[2]
        SETUP    F first[2]
        SETUP    F second[2]
        Test/test_54044536_2.py::test_double_fixture[2-2] (fixtures used: first, second)F
        TEARDOWN F second[2]
        TEARDOWN F first[2]

like image 54
Insspb Avatar answered Sep 21 '22 14:09

Insspb