Test class using page objects in Selenium Python - Build an Automation Script
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: URL = "https://example.com/login" USERNAME_INPUT = (By.ID, "username") PASSWORD_INPUT = (By.ID, "password") LOGIN_BUTTON = (By.ID, "loginBtn") def __init__(self, driver): self.driver = driver def load(self): self.driver.get(self.URL) def enter_username(self, username): WebDriverWait(self.driver, 10).until( EC.visibility_of_element_located(self.USERNAME_INPUT) ).send_keys(username) def enter_password(self, password): WebDriverWait(self.driver, 10).until( EC.visibility_of_element_located(self.PASSWORD_INPUT) ).send_keys(password) def click_login(self): login_button = WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable(self.LOGIN_BUTTON) ) login_button.click() class TestLogin(unittest.TestCase): def setUp(self): self.driver = webdriver.Chrome() self.driver.maximize_window() self.login_page = LoginPage(self.driver) def test_valid_login(self): self.login_page.load() self.login_page.enter_username("testuser") self.login_page.enter_password("Test@1234") self.login_page.click_login() WebDriverWait(self.driver, 10).until( EC.url_contains("/dashboard") ) current_url = self.driver.current_url self.assertIn("/dashboard", current_url, "Dashboard URL not found after login") def tearDown(self): self.driver.quit() if __name__ == "__main__": unittest.main()
This test uses the Page Object Model to keep the login page elements and actions in the LoginPage class. This makes the test code cleaner and easier to maintain.
The LoginPage class defines locators as tuples using By.ID for better readability and maintainability.
Explicit waits (WebDriverWait) ensure the test waits for elements to be visible or clickable before interacting, avoiding flaky tests.
The test class TestLogin uses Python's unittest framework for structure and assertions.
Setup and teardown methods open and close the browser for each test, ensuring a clean state.
The test verifies the URL contains '/dashboard' after login to confirm success.
Now add data-driven testing with 3 different sets of username and password inputs to test multiple login scenarios.
Practice
Solution
Step 1: Understand page object role
Page objects hold locators and page actions, separating them from test logic.Step 2: Recognize test class role
Test classes use page objects to perform actions and assertions, improving readability and maintenance.Final Answer:
To separate page details from test logic for easier maintenance -> Option AQuick Check:
Page objects separate page details = C [OK]
- Thinking tests should contain locators directly
- Believing page objects speed up test execution
- Confusing page objects with test runners
Solution
Step 1: Check class and constructor syntax
class LoginPage: def __init__(self, driver): self.driver = driver self.username_input = driver.find_element(By.ID, 'username') correctly defines a class with __init__ accepting driver and assigns driver to self.driver.Step 2: Verify locator usage
class LoginPage: def __init__(self, driver): self.driver = driver self.username_input = driver.find_element(By.ID, 'username') uses driver.find_element with By.ID and locator string, which is correct Selenium syntax.Final Answer:
Correct page object class with driver parameter and locator using By.ID -> Option CQuick Check:
Class with __init__(driver) and By.ID locator = A [OK]
- Missing driver parameter in __init__
- Using driver.find_element without By selector
- Defining page object as a function instead of class
class LoginPage:
def __init__(self, driver):
self.driver = driver
def get_title(self):
return self.driver.title
class TestLogin:
def test_title(self, driver):
page = LoginPage(driver)
print(page.get_title())
# Assume driver.title = 'Login Page'Solution
Step 1: Understand get_title method
get_title returns driver.title, which is 'Login Page' as given.Step 2: Check test_title method output
test_title creates LoginPage instance and prints get_title result, so it prints 'Login Page'.Final Answer:
Login Page -> Option BQuick Check:
page.get_title() returns 'Login Page' [OK]
- Confusing method return with attribute name
- Assuming print outputs None
- Thinking driver is undefined inside test method
class LoginPage:
def __init__(self, driver):
self.driver = driver
def enter_username(self, username):
self.driver.find_element(By.ID, 'username').send_keys(username)
class TestLogin:
def test_enter_username(self, driver):
page = LoginPage()
page.enter_username('user1')Solution
Step 1: Check LoginPage instantiation
LoginPage requires driver argument in __init__, but called without arguments in test_enter_username.Step 2: Verify other code parts
send_keys usage and By.ID locator are correct; test_enter_username has self parameter as method of class.Final Answer:
LoginPage is instantiated without driver argument -> Option AQuick Check:
Missing driver argument in LoginPage() call = B [OK]
- Forgetting to pass driver to page object constructor
- Assuming send_keys needs different syntax
- Confusing locator syntax errors
Solution
Step 1: Understand page object responsibility
Page objects should provide methods that check element states like visibility and clickability.Step 2: Understand test class responsibility
Test class uses page object methods to assert expected conditions, keeping test logic separate from page details.Final Answer:
Page object has method is_login_button_clickable() returning True/False; test class asserts this method's result -> Option DQuick Check:
Page object checks state, test asserts result = D [OK]
- Mixing locator logic inside test class
- Not returning boolean from page object methods
- Ignoring visibility checks in tests
Ready to prove it?
Pass the test and this pattern moves unknown
