Rocky Wang
Rocky Wang

Reputation: 51

How to run a fixture in a test case twice with pytest?

Here I use this fixture to generate a network obj with a iprange. While in some cases, I need to generate 2 different networks in the same test.

@pytest.fixture(scope="function")
def fixture_user_create_network_with_iprange(get_user_token,
                                          fixture_user_create_network,
                                          fixture_user_create_iprange,
                                          request):
    token = get_user_token
    network_uuid = fixture_user_create_network
    iprange_uuid = fixture_user_create_iprange
    add_ipranges_to_networks(token,network_uuid,iprange_uuid)

    return network_uuid

But in the same test the fixture can only run once. I create another fixture named fixture_user_create_2nd_network_with_iprange, it is a copy of original fixture, but different name.

Becuase of these 2 fixture are also using fixture_user_create_network, fixture_user_create_iprange, which only run once in a test. I got only one network obj.

So I want to know,

Upvotes: 5

Views: 4218

Answers (2)

Dunk
Dunk

Reputation: 1406

You can use mark.parametrize with the "indirect" switch to allow a cardinality parameter to be passed to your fixture, and then just return that number of copies of it:

@pytest.fixture
def data_repeated(request):
    return [deepcopy({'a': 1, 'b': 2}) for _ in range(request.param)]


@pytest.mark.parametrize('data_repeated', [3], indirect=['data_repeated'])
def test(data_repeated):
    assert data_repeated == [
        {'a': 1, 'b': 2},
        {'a': 1, 'b': 2},
        {'a': 1, 'b': 2}]

Upvotes: 0

Sergey Vasilyev
Sergey Vasilyev

Reputation: 4189

You cannot run a single fixture twice. This is against the concept of the fixtures.

However, you can extract the network_uuid preparation into a function (just function), and declare 2+ fixtures that call it.

You can also call the fixtures dynamically:

@pytest.fixture
def fixt1(request):
    return 'hello'

@pytest.fixture
def fixt2(request):
    return request.getfuncargvalue('fixt1')

def test_me(fixt2):
    assert fixt2 == 'hello'

But still, only once per test.

If you want a dynamic amount of similar fixtures, you can generate them:

import pytest

# Just for proper var closures:
def _make_fixt_fn(i):
    @pytest.fixture
    def fixt_fn(....):
        return 'fixt{}'.format(i)
    return fixt_fn

# The fixtures must reside in the module's namespace. The decorator is just a mark.
for i in range(1, 4):
    name = 'dyn_fixt_{}'.format(i)
    global()[name] = _make_fixt_fn(i)

def test_dyn(dyn_fixt_1, dyn_fixt_2, dyn_fixt_3):
    pass

Lets check:

$ pytest test_dyn.py --fixtures
...
------- fixtures defined from test_dyn ----------
dyn_fixt_1
    test_dyn.py:6: no docstring available
dyn_fixt_2
    test_dyn.py:6: no docstring available
dyn_fixt_3
    test_dyn.py:6: no docstring available

Upvotes: 1

Related Questions