user9074332
user9074332

Reputation: 2636

Pytest parametrize a test using a fixture

I am trying to better understand how to thoroughly unit test using pytest and came across a situation that I am not sure how to best approach. I found similar questions here on SO about parameterizing fixtures themselves but I don't think that is what I want to do here. But maybe I am not fully understanding fixtures themselves?

Here is some sample code:

App Code:

class Person:
    def __init__(self, fname: str, lname: str):
        self.fname = fname
        self.lname = lname

    def upper_fullname(self):
        return f'{self.fname} {self.lname}'.upper()

Tests:

import pytest

@pytest.fixture(scope="module")
def fixture_mm(conf={"fname": "mickey", "lname": "mouse"}):
    return Person(**conf)

@pytest.fixture(scope="module")
def fixture_bb(conf={"fname": "bugs", "lname": "bunny"}):
    return Person(**conf)

@pytest.mark.parametrize(
    'person, expected_result',
    [(fixture_mm, "MICKEY MOUSE"), (fixture_bb, "BUGS BUNNY")])
def test_uppernames(person, expected_result):
    assert person.upper_fullname() == expected_result

I would expect both of these tests to pass but instead I get an error message saying AttributeError: 'function' object has no attribute 'upper_fullname'. What am I missing here?

Thanks.

Upvotes: 1

Views: 188

Answers (1)

Norrius
Norrius

Reputation: 7930

You're getting an error because fixture_mm is a function. You need to call a function to get a value (fixture_mm()), but this is not going to work with fixtures.

But I don't think you even need fixtures here. You could make these into normal functions and use them like this:

def person_mm(conf={"fname": "mickey", "lname": "mouse"}):
    return Person(**conf)

def person_bb(conf={"fname": "bugs", "lname": "bunny"}):
    return Person(**conf)

@pytest.mark.parametrize(
    'person, expected_result',
    [(person_mm(), "MICKEY MOUSE"), (person_bb(), "BUGS BUNNY")])
def test_uppernames(person, expected_result):
    assert person.upper_fullname() == expected_result

Caveat: since fixture parameters are evaluated at the module compile time, this might cause issues if the functions require some setup. On the other hand, if your functions are as simple as in this example, you could even save these objects as constants:

PERSON_MM = Person(fname="mickey", lname="mouse")
PERSON_BB = Person(fname="bugs", lname="bunny")

Upvotes: 2

Related Questions