Parametrized fixtures in PyTest - Build an Automation Script
import pytest from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC @pytest.fixture(params=[ {"username": "user1@example.com", "password": "Pass123!"}, {"username": "user2@example.com", "password": "Pass456!"}, {"username": "user3@example.com", "password": "Pass789!"} ]) def credentials(request): return request.param @pytest.fixture def driver(): driver = webdriver.Chrome() driver.implicitly_wait(5) yield driver driver.quit() def test_login_with_parametrized_credentials(driver, credentials): driver.get("http://example.com/login") # Wait for username field and enter username username_field = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.ID, "username")) ) username_field.clear() username_field.send_keys(credentials["username"]) # Wait for password field and enter password password_field = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.ID, "password")) ) password_field.clear() password_field.send_keys(credentials["password"]) # Wait for login button and click login_button = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.ID, "loginBtn")) ) login_button.click() # Verify URL contains '/dashboard' WebDriverWait(driver, 10).until( EC.url_contains("/dashboard") ) assert "/dashboard" in driver.current_url # Verify logout button is present logout_button = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "logoutBtn")) ) assert logout_button.is_displayed() # Logout to reset state logout_button.click()
This test uses a pytest parametrized fixture named credentials to supply three different sets of user login data.
The driver fixture sets up the Selenium WebDriver and ensures it quits after the test.
The test function test_login_with_parametrized_credentials uses these fixtures. It opens the login page, waits explicitly for each element to be clickable before interacting, and enters the username and password from the current parameter set.
After clicking login, it waits until the URL contains '/dashboard' to confirm successful login, then asserts this condition.
It also checks that the logout button is visible, confirming the user is logged in.
Finally, it clicks logout to reset the state for the next test iteration.
This approach keeps tests clean, readable, and reliable by using explicit waits and parametrization.
Now add data-driven testing with 3 different sets of invalid credentials and verify login failure message.
Practice
@pytest.fixture(params=[...]) in pytest?Solution
Step 1: Understand the role of parametrized fixtures
Parametrized fixtures allow running a test function multiple times with different data inputs automatically.Step 2: Match the purpose with the options
To run the same test multiple times with different input data correctly describes this behavior, while others describe unrelated pytest features.Final Answer:
To run the same test multiple times with different input data -> Option AQuick Check:
Parametrized fixtures = run test multiple times [OK]
- Confusing parametrized fixtures with test skipping
- Thinking it groups tests instead of repeating them
- Mixing up with expected failure markers
Solution
Step 1: Identify correct decorator and parameter name
The correct decorator is@pytest.fixturewith the keywordparamsas a list.Step 2: Check function signature and usage
The fixture function must acceptrequestand returnrequest.paramto access each parameter value.Final Answer:
@pytest.fixture(params=[1, 2, 3])\ndef data(request):\n return request.param -> Option CQuick Check:
Use @pytest.fixture(params=[...]) and request.param [OK]
- Using @pytest.param instead of @pytest.fixture
- Misspelling 'params' as 'param'
- Not including 'request' parameter in fixture function
- Returning undefined variable instead of request.param
import pytest
@pytest.fixture(params=[10, 20])
def number(request):
return request.param
def test_double(number):
assert number * 2 in [20, 40]Solution
Step 1: Understand parametrized fixture values
The fixture 'number' will run the test twice: once with 10, once with 20.Step 2: Evaluate the assertion for each value
For 10: 10*2=20, which is in [20,40]. For 20: 20*2=40, also in [20,40]. Both assertions pass.Final Answer:
Both tests pass -> Option DQuick Check:
10*2=20 and 20*2=40 both in list [OK]
- Assuming only one test runs
- Misreading the assertion condition
- Forgetting fixture runs test multiple times
@pytest.fixture(params=["a", "b"])
def letter():
return param
def test_letter(letter):
assert letter in ["a", "b"]Solution
Step 1: Check fixture function parameters
The fixture usesparams, so it must acceptrequestto accessrequest.param.Step 2: Identify incorrect return statement
The function returnsparam, which is undefined. It should returnrequest.param.Final Answer:
Missing 'request' parameter in fixture function -> Option BQuick Check:
Parametrized fixture needs 'request' param [OK]
- Not including 'request' parameter in fixture
- Returning undefined variable instead of request.param
- Confusing fixture decorator names
Solution
Step 1: Understand skipping inside parametrized fixtures
Inside the fixture, you can callpytest.skip()when the current parameter is invalid to skip that test run.Step 2: Compare with other options
Removing invalid data beforehand avoids testing them but doesn't show skipped tests. Raising exceptions fails tests, not skip. Usingskipifon test function is less flexible for per-parameter skipping.Final Answer:
Use pytest.skip() inside the fixture when data is invalid -> Option AQuick Check:
Call pytest.skip() in fixture to skip invalid params [OK]
- Removing invalid data silently instead of skipping
- Raising exceptions instead of skipping
- Using skipif without parameter-specific logic
Ready to prove it?
Pass the test and this pattern moves unknown
