pan8863
pan8863

Reputation: 733

py.test parameterized fixtures

I am currently working on some unit test cases and test fixtures using py.test

I have some code that does this:

# my py.test file
import pytest

@pytest.fixture
def fixture_1():
    f = open("file_one.txt", 'rb')
    f_str = f.read()
    yield f_str
    f.close()

def test_function_1(fixture_1):
    assert fixture_1.startswith("some_test_data") # example test

This is all good and works fine.

Now let's say I write another test function that works with input stored in another file (let's say file_two.txt and my function is like this:

# in same py file as above
def test_function_2(fixture_1):
     #some test with data from file_two.txt
     assert something_for_fun

In the test_function_2 above, i want to fixture_1 to do the same operations as before but on file_two.txt instead of file_one.txt.

EDIT : I also played with parametrizing fixtures but that invokes my test_function_* as many times as the number of arguments to the fixture, which doesn't work since the test_functions are specific to the input from a file.

I read about the the request fixture, but not sure how to use it to inspect the context of a test function.

If anyone has that figured out, please let me know. Meanwhile I will post as soon as i get it working!

EDIT 2: I also know about inspect and introspect BUT i am looking for a cleaner way to do this, preferably by using some pytest magic~

Thanks!

Upvotes: 4

Views: 1262

Answers (1)

hoefling
hoefling

Reputation: 66171

You can parametrize the fixture from test and read the passed parameter via request.param:

import pytest

@pytest.fixture
def fixture_1(request):
    filename = request.param
    with open(filename) as f:
        f_str = f.read()
    yield f_str


@pytest.mark.parametrize('fixture_1', ['file_one.txt'], indirect=True)
def test_function_1(fixture_1):
    assert fixture_1.startswith("some_test_data") # example test


@pytest.mark.parametrize('fixture_1', ['file_two.txt'], indirect=True)
def test_function_2(fixture_1):
    assert something_for_fun

Test run should yield:

test_module.py::test_function_1[file_one.txt] PASSED
test_module.py::test_function_2[file_two.txt] PASSED

You can also set up a default fixture value for the filename and parametrize on demand:

@pytest.fixture
def fixture_1(request):
    filename = getattr(request, 'param', 'file_one.txt')
    with open(filename) as f:
        f_str = f.read()
    yield f_str


def test_function_1(fixture_1):
    assert fixture_1.startswith("some_test_data") # example test


@pytest.mark.parametrize('fixture_1', ['file_two.txt'], indirect=True)
def test_function_2(fixture_1):
    assert fixture_1.startswith('bar')

Now test_function_1 stays unparametrized:

test_module.py::test_function_1 PASSED
test_module.py::test_function_2[file_two.txt] PASSED

Upvotes: 3

Related Questions