Bird
Raised Fist0
Selenium Pythontesting~15 mins

Data providers pattern in Selenium Python - Build an Automation Script

Choose your learning style10 modes available
Login functionality test with multiple user credentials
Preconditions (2)
Step 1: Open the login page URL.
Step 2: For each set of credentials:
Step 3: - Enter the username in the username input field with id 'username'.
Step 4: - Enter the password in the password input field with id 'password'.
Step 5: - Click the login button with id 'loginBtn'.
Step 6: - Verify the result:
Step 7: - If credentials are valid, the URL should change to 'https://example.com/dashboard'.
Step 8: - If credentials are invalid, an error message with id 'errorMsg' should be visible.
✅ Expected Result: For each credential set, the login behaves correctly: successful login redirects to dashboard, failed login shows error message.
Automation Requirements - selenium with unittest
Assertions Needed:
Assert current URL is dashboard URL for valid credentials
Assert error message is displayed for invalid credentials
Best Practices:
Use data provider pattern to supply multiple credentials
Use explicit waits to wait for elements or URL changes
Use Page Object Model to separate page interactions
Keep test code clean and readable
Automated Solution
Selenium Python
import unittest
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

class LoginPage:
    def __init__(self, driver):
        self.driver = driver
        self.url = 'https://example.com/login'
        self.username_input = (By.ID, 'username')
        self.password_input = (By.ID, 'password')
        self.login_button = (By.ID, 'loginBtn')
        self.error_message = (By.ID, 'errorMsg')

    def load(self):
        self.driver.get(self.url)

    def login(self, username, password):
        WebDriverWait(self.driver, 10).until(
            EC.visibility_of_element_located(self.username_input)
        )
        self.driver.find_element(*self.username_input).clear()
        self.driver.find_element(*self.username_input).send_keys(username)
        self.driver.find_element(*self.password_input).clear()
        self.driver.find_element(*self.password_input).send_keys(password)
        self.driver.find_element(*self.login_button).click()

    def is_error_displayed(self):
        try:
            return WebDriverWait(self.driver, 5).until(
                EC.visibility_of_element_located(self.error_message)
            ) is not None
        except:
            return False

class TestLogin(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.driver = webdriver.Chrome()
        cls.driver.implicitly_wait(5)
        cls.login_page = LoginPage(cls.driver)

    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()

    def data_provider(self):
        return [
            ('validUser1', 'validPass1', True),
            ('invalidUser', 'invalidPass', False),
            ('validUser2', 'wrongPass', False)
        ]

    def test_login_with_multiple_credentials(self):
        for username, password, is_valid in self.data_provider():
            with self.subTest(username=username, password=password):
                self.login_page.load()
                self.login_page.login(username, password)
                if is_valid:
                    WebDriverWait(self.driver, 10).until(
                        EC.url_to_be('https://example.com/dashboard')
                    )
                    current_url = self.driver.current_url
                    self.assertEqual(current_url, 'https://example.com/dashboard',
                                     f'Expected dashboard URL for valid user {username}')
                else:
                    self.assertTrue(self.login_page.is_error_displayed(),
                                    f'Error message should be displayed for invalid user {username}')

This test script uses Selenium with Python's unittest framework.

We define a LoginPage class as a Page Object to handle page actions and locators. This keeps code clean and reusable.

The data_provider method returns multiple sets of username, password, and expected validity.

The test method test_login_with_multiple_credentials loops over these data sets using subTest for clear reporting.

For valid credentials, it waits until the URL changes to the dashboard and asserts it matches.

For invalid credentials, it checks if the error message is visible.

Explicit waits ensure the test waits for elements or URL changes properly, avoiding flaky tests.

Setup and teardown methods open and close the browser once for all tests.

Common Mistakes - 4 Pitfalls
{'mistake': 'Hardcoding waits with time.sleep instead of using explicit waits', 'why_bad': 'Using fixed sleep times can make tests slow or flaky if the page loads faster or slower than expected.', 'correct_approach': "Use Selenium's explicit waits like WebDriverWait with expected_conditions to wait only as long as needed."}
Not clearing input fields before sending keys
Mixing locators or using brittle XPath selectors
Not using data-driven approach and writing separate tests for each credential
Bonus Challenge

Now add data-driven testing with 3 different inputs using unittest's subTest and parameterize the test method.

Show Hint

Practice

(1/5)
1. What is the main purpose of using the data providers pattern in Selenium Python tests?
easy
A. To generate test reports in different formats
B. To speed up the browser loading time
C. To create new test cases automatically
D. To run the same test multiple times with different input data

Solution

  1. Step 1: Understand the data providers pattern

    The data providers pattern allows running one test repeatedly with different sets of data.
  2. Step 2: Identify the main benefit

    This helps find more bugs by testing various inputs without writing separate tests.
  3. Final Answer:

    To run the same test multiple times with different input data -> Option D
  4. Quick Check:

    Data providers = run test many times with different data [OK]
Hint: Remember: data providers = repeat test with new data [OK]
Common Mistakes:
  • Thinking data providers speed up browser loading
  • Confusing data providers with automatic test creation
  • Believing data providers generate reports
2. Which of the following is the correct syntax to use a data provider in pytest for Selenium Python?
easy
A. @pytest.mark.parametrize('input', ['data1', 'data2'])
B. @pytest.run_with_data(['data1', 'data2'])
C. @pytest.test_data(['data1', 'data2'])
D. @pytest.data_provider(['data1', 'data2'])

Solution

  1. Step 1: Recall pytest data provider syntax

    Pytest uses @pytest.mark.parametrize to supply multiple data sets to a test function.
  2. Step 2: Match the correct syntax

    @pytest.mark.parametrize('input', ['data1', 'data2']) correctly shows @pytest.mark.parametrize('input', ['data1', 'data2']).
  3. Final Answer:

    @pytest.mark.parametrize('input', ['data1', 'data2']) -> Option A
  4. Quick Check:

    Pytest data provider = @pytest.mark.parametrize [OK]
Hint: Look for @pytest.mark.parametrize for data providers [OK]
Common Mistakes:
  • Using non-existent decorators like @pytest.data_provider
  • Confusing parametrize with test_data or run_with_data
  • Missing quotes around parameter names
3. What will be the output of the following pytest test using data providers?
import pytest

@pytest.mark.parametrize('num', [1, 2, 3])
def test_is_positive(num):
    assert num > 0
medium
A. All tests pass
B. All tests fail
C. Only the test with num=1 passes
D. Syntax error occurs

Solution

  1. Step 1: Analyze the test logic

    The test asserts that the input number is greater than zero.
  2. Step 2: Check each data value

    Values 1, 2, and 3 are all greater than zero, so all assertions pass.
  3. Final Answer:

    All tests pass -> Option A
  4. Quick Check:

    All nums > 0, so tests pass [OK]
Hint: Check if all inputs satisfy the assertion [OK]
Common Mistakes:
  • Assuming some inputs fail without checking values
  • Thinking syntax error due to parametrize
  • Ignoring that all numbers are positive
4. Identify the error in this pytest data provider usage:
@pytest.mark.parametrize('input', [1, 2, 3])
def test_example():
    assert input > 0
medium
A. Wrong decorator name
B. Missing parameter in test function definition
C. List of inputs should be strings
D. Assertion syntax is incorrect

Solution

  1. Step 1: Check test function parameters

    The test function must accept the parameter named in parametrize, here 'input'.
  2. Step 2: Identify missing parameter

    The function test_example() has no parameters, so 'input' is undefined inside it.
  3. Final Answer:

    Missing parameter in test function definition -> Option B
  4. Quick Check:

    Parametrize param must match function argument [OK]
Hint: Function must accept all parametrize arguments [OK]
Common Mistakes:
  • Forgetting to add parameter to test function
  • Using wrong decorator name
  • Thinking input list must be strings
  • Misreading assertion syntax
5. You want to test a login form with multiple username and password pairs using data providers in pytest. Which approach correctly handles multiple parameters?
hard
A. @pytest.mark.parametrize('username', ['user1', 'user2']) @pytest.mark.parametrize('password', ['pass1', 'pass2']) def test_login(username, password): assert username and password
B. @pytest.mark.parametrize('username_password', [('user1', 'pass1'), ('user2', 'pass2')]) def test_login(username_password): assert username_password[0] and username_password[1]
C. @pytest.mark.parametrize(('username', 'password'), [('user1', 'pass1'), ('user2', 'pass2')]) def test_login(username, password): assert username and password
D. @pytest.mark.parametrize('username', ['user1', 'user2'], 'password', ['pass1', 'pass2']) def test_login(username, password): assert username and password

Solution

  1. Step 1: Understand multiple parameter usage in parametrize

    To pass multiple parameters together, use a tuple of parameter names and a list of tuples with values.
  2. Step 2: Identify correct syntax

    @pytest.mark.parametrize(('username', 'password'), [('user1', 'pass1'), ('user2', 'pass2')]) def test_login(username, password): assert username and password uses @pytest.mark.parametrize(('username', 'password'), [('user1', 'pass1'), ('user2', 'pass2')]), which is correct.
  3. Final Answer:

    Use tuple of parameter names and list of tuples for values -> Option C
  4. Quick Check:

    Multiple params = tuple names + list of tuples [OK]
Hint: Use tuple of names and list of tuples for multiple params [OK]
Common Mistakes:
  • Stacking multiple parametrize decorators incorrectly
  • Passing multiple parameters in one string without tuple
  • Wrong syntax with multiple lists in one decorator
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard