Why data-driven tests increase coverage in Selenium Python - Automation Benefits in Action
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.username_input = (By.ID, 'username') self.password_input = (By.ID, 'password') self.login_button = (By.ID, 'loginBtn') def enter_username(self, username): WebDriverWait(self.driver, 10).until( EC.visibility_of_element_located(self.username_input) ).clear() self.driver.find_element(*self.username_input).send_keys(username) def enter_password(self, password): WebDriverWait(self.driver, 10).until( EC.visibility_of_element_located(self.password_input) ).clear() self.driver.find_element(*self.password_input).send_keys(password) def click_login(self): WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable(self.login_button) ).click() class DashboardPage: def __init__(self, driver): self.driver = driver self.logout_button = (By.ID, 'logoutBtn') def is_loaded(self): return WebDriverWait(self.driver, 10).until( EC.url_contains('/dashboard') ) def logout(self): WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable(self.logout_button) ).click() class TestLoginDataDriven(unittest.TestCase): def setUp(self): self.driver = webdriver.Chrome() self.driver.get('https://example.com/login') self.login_page = LoginPage(self.driver) self.dashboard_page = DashboardPage(self.driver) def test_login_multiple_users(self): test_data = [ {'username': 'user1@example.com', 'password': 'Password1!'}, {'username': 'user2@example.com', 'password': 'Password2!'}, {'username': 'user3@example.com', 'password': 'Password3!'} ] for data in test_data: with self.subTest(data=data): self.login_page.enter_username(data['username']) self.login_page.enter_password(data['password']) self.login_page.click_login() self.assertTrue(self.dashboard_page.is_loaded(), f"Dashboard did not load for {data['username']}") self.dashboard_page.logout() # After logout, verify we are back on login page self.assertIn('/login', self.driver.current_url) def tearDown(self): self.driver.quit() if __name__ == '__main__': unittest.main()
This test script uses Selenium with Python's unittest framework to automate login tests with multiple user credentials.
The LoginPage class encapsulates the login page elements and actions, using explicit waits to ensure elements are ready before interacting.
The DashboardPage class checks if the dashboard page loaded by waiting for the URL to contain '/dashboard' and provides a logout method.
The test test_login_multiple_users runs the login steps for three different users using a data-driven approach with a list of dictionaries. It uses subTest to isolate each data set.
Assertions verify that after login the dashboard page loads and after logout the user returns to the login page.
Explicit waits improve reliability by waiting for elements to be ready.
Using Page Object Model keeps locators and actions organized and reusable.
This approach increases test coverage by verifying the login works correctly for multiple users without duplicating code.
Now add data-driven testing with 3 different invalid login inputs and verify error messages appear
Practice
Solution
Step 1: Understand data-driven testing concept
Data-driven tests repeat the same test steps but use different input data sets.Step 2: Connect data variation to coverage
Using many inputs helps test more scenarios, increasing coverage and finding more bugs.Final Answer:
Because they run the same test steps with many different inputs -> Option DQuick Check:
Data-driven tests = many inputs = more coverage [OK]
- Thinking data-driven tests reduce test cases
- Confusing UI layout testing with data-driven testing
- Believing data-driven tests skip validations
Solution
Step 1: Recall pytest parameterization syntax
The correct decorator is @pytest.mark.parametrize with 'param' and list of values.Step 2: Check each option syntax
Only @pytest.mark.parametrize('input', [1, 2, 3]) uses correct spelling and syntax: @pytest.mark.parametrize('input', [1, 2, 3]).Final Answer:
@pytest.mark.parametrize('input', [1, 2, 3]) -> Option CQuick Check:
Correct pytest decorator = @pytest.mark.parametrize [OK]
- Misspelling 'parametrize' as 'parametrize' or 'parametrized'
- Using parentheses instead of brackets for data list
- Confusing 'param' and 'parametrize'
import pytest
@pytest.mark.parametrize('num', [1, 2, 3])
def test_is_even(num):
assert num % 2 == 0Solution
Step 1: Understand the test logic
The test asserts num % 2 == 0, meaning num must be even.Step 2: Check each input
Input 1: 1 % 2 = 1 (fail), Input 2: 2 % 2 = 0 (pass), Input 3: 3 % 2 = 1 (fail).Final Answer:
Test fails for inputs 1 and 3 -> Option BQuick Check:
Odd numbers fail assertion [OK]
- Assuming only input 3 fails
- Thinking all inputs pass
- Confusing modulo operation results
@pytest.mark.parametrize('username, password', [('user1', 'pass1'), ('user2', 'pass2')])
def test_login(username, password):
driver.get('http://example.com/login')
driver.find_element(By.ID, 'username').send_keys(username)
driver.find_element(By.ID, 'password').send_keys(password)
driver.find_element(By.ID, 'submit').click()
assert driver.find_element(By.ID, 'welcome').is_displayed()Solution
Step 1: Review code for missing imports
The code uses By.ID but does not show import of By from selenium.webdriver.common.by.Step 2: Check other code parts
Parameter names match, send_keys used correctly on input fields, assertion checks welcome element display.Final Answer:
Missing import for By locator -> Option AQuick Check:
Using By requires importing it [OK]
- Assuming parameter names are wrong
- Thinking send_keys is used on button
- Missing assertion is incorrect here
Solution
Step 1: Understand test maintenance challenges
Writing separate tests for each input is time-consuming and hard to maintain.Step 2: Explain data-driven test advantage
Data-driven tests reuse the same test code with different inputs, making it easy to add or change data without rewriting code.Final Answer:
By allowing reuse of test logic with new data sets without rewriting tests -> Option AQuick Check:
Reuse test logic + new data = easier maintenance [OK]
- Thinking each input needs a new test function
- Believing data-driven tests reduce assertions
- Assuming data-driven tests limit data sets
Ready to prove it?
Pass the test and this pattern moves unknown
