Setting up and tearing down identical fixtures with very minor changes leads to code repetition and maintenance nightmare.
It’s all possible, and the answer lies in Pytest fixtures with arguments.
Parameterized Fixture
# Define a fixture with parameters
@pytest.fixture(params=[0, 1, 2])
def param_data(request):
return request.param
# Test parametrized fixture
def test_param_data(param_data):
assert param_data in [0, 1, 2]
In the above code, we pass the @pytest.fixture(params=[0, 1, 2])
marker to our param_data
fixture and made use of the request
argument within our fixture.
Fixture With Argument (Indirect parametrization)
What if you don’t want to define the parameters in the fixture but rather in the test?
Use indirect parametrization to pass arguments to the fixture
@pytest.mark.parametrize("square", [1, 2, 3], indirect=True)
def test_square(square):
assert square in [2, 4, 6]
In our test, we use the indirect=True
argument to tell Pytest to pass this parameter to the square
fixture.
Factories As Fixtures
Factories, in the context of Pytest fixtures, are functions that are used to create and return instances of objects that are needed for testing.
# tests/test_basic_example.py
@pytest.fixture
def user_creds():
def _user_creds(name: str, email: str):
return {"name": name, "email": email}
return _user_creds
def test_user_creds(user_creds):
assert user_creds("John", "abc@xyz.com") == {
"name": "John",
"email": "abc@xyz.com",
}
Simulating User Actions:
For UI testing or user interaction testing, you may want to pass arguments to fixtures to simulate different user actions or scenarios.
@pytest.fixture
def user_actions():
def perform_user_action(action_type):
if action_type == "login":
# Simulate user login
elif action_type == "logout":
# Simulate user logout
else:
raise ValueError("Invalid action type")
return perform_user_action
def test_user_login(user_actions):
user_actions("login")
# Test user login behavior
# Additional assertions and test logic here