0
0
Selenium Pythontesting~15 mins

Test class using page objects in Selenium Python - Deep Dive

Choose your learning style9 modes available
Overview - Test class using page objects
What is it?
A test class using page objects is a way to organize automated tests by separating the test logic from the details of the web page structure. It uses special classes called page objects that represent web pages or parts of them, with methods to interact with page elements. This makes tests easier to read, maintain, and update when the web page changes. It helps beginners write clear and reusable test code.
Why it matters
Without page objects, test code mixes test steps with details about how to find and interact with page elements. This makes tests hard to read and break easily when the page changes. Using page objects solves this by keeping page details in one place, so tests stay clean and stable. This saves time and reduces errors in real projects where web pages often change.
Where it fits
Before learning this, you should know basic Selenium commands and how to write simple tests. After this, you can learn advanced test design patterns, test frameworks like pytest, and continuous integration to run tests automatically.
Mental Model
Core Idea
A test class using page objects separates test steps from page details by using classes that represent pages, making tests clearer and easier to maintain.
Think of it like...
It's like having a remote control for a TV: instead of pressing buttons directly on the TV, you use the remote which knows how to control the TV. If the TV changes, you only need to update the remote, not relearn how to watch shows.
┌───────────────┐       ┌───────────────┐       ┌───────────────┐
│   Test Class  │──────▶│  Page Object  │──────▶│ Web Page DOM  │
│ (test steps)  │       │ (page methods)│       │ (elements)    │
└───────────────┘       └───────────────┘       └───────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding basic Selenium tests
🤔
Concept: Learn how to write simple Selenium tests that open a page and check something.
Use Selenium WebDriver to open a browser, navigate to a URL, find an element by its locator, and check its text or state. For example, open a login page and check the title.
Result
You can write a test that opens a page and verifies expected content.
Knowing how Selenium commands work is essential before organizing tests with page objects.
2
FoundationWhat is a page object class?
🤔
Concept: Introduce the idea of a class that represents a web page with methods for actions and element locators.
A page object class has locators as variables and methods that perform actions like clicking buttons or entering text. This hides the details of how elements are found.
Result
You create a reusable class that models a page, making test code cleaner.
Separating page details into a class reduces duplication and makes tests easier to update.
3
IntermediateWriting a page object for a login page
🤔Before reading on: do you think the page object should include assertions or only actions? Commit to your answer.
Concept: Build a page object class for a login page with methods to enter username, password, and submit the form.
Define locators for username input, password input, and login button. Write methods like enter_username(text), enter_password(text), and click_login(). Use Selenium's find_element with By.ID or By.NAME.
Result
You have a class that can perform login steps without exposing locators in tests.
Keeping assertions out of page objects keeps them reusable and focused on page interactions.
4
IntermediateCreating a test class using page objects
🤔Before reading on: should the test class create the WebDriver or receive it from outside? Commit to your answer.
Concept: Write a test class that uses the login page object to perform a login test with assertions.
In the test class, create a WebDriver instance, create the login page object passing the driver, call page methods to enter credentials and submit, then assert the expected result like a welcome message or URL change.
Result
Tests become readable sequences of high-level actions and checks.
Separating test logic from page details improves clarity and makes tests easier to maintain.
5
IntermediateUsing setup and teardown in test classes
🤔
Concept: Learn to use setup and teardown methods to open and close the browser before and after tests.
Use unittest's setUp and tearDown methods to create and quit the WebDriver. This avoids repeating code in each test method and ensures clean test runs.
Result
Tests run reliably with browser management handled automatically.
Managing browser lifecycle in one place prevents resource leaks and flaky tests.
6
AdvancedHandling dynamic elements in page objects
🤔Before reading on: do you think locators should be hardcoded or flexible for dynamic pages? Commit to your answer.
Concept: Learn to write page object methods that handle elements which may appear or change dynamically.
Use explicit waits like WebDriverWait to wait for elements to be visible or clickable before interacting. Encapsulate waits inside page object methods to keep tests simple.
Result
Tests become more stable and less likely to fail due to timing issues.
Encapsulating waits inside page objects hides complexity and improves test reliability.
7
ExpertDesigning scalable page object hierarchies
🤔Before reading on: should all page objects be flat or can they inherit from base classes? Commit to your answer.
Concept: Explore advanced design where page objects inherit from base classes to share common methods and locators.
Create a BasePage class with common methods like wait_for_element or get_title. Other page objects inherit from BasePage and add page-specific methods. This reduces code duplication and eases maintenance in large projects.
Result
Page objects are organized, reusable, and easier to extend as the application grows.
Using inheritance in page objects supports scalable test automation architectures.
Under the Hood
Page objects work by wrapping Selenium WebDriver calls inside methods that represent user actions or queries on a page. When a test calls a page object method, it triggers WebDriver to find elements using locators and perform actions like click or send keys. This hides the raw WebDriver calls from tests, centralizing element locators and interaction logic.
Why designed this way?
Page objects were designed to solve the problem of brittle and hard-to-maintain tests caused by mixing test logic with page details. By isolating page structure and interaction in dedicated classes, tests become more readable and resilient to UI changes. Alternatives like writing raw Selenium commands in tests were error-prone and duplicated code.
┌───────────────┐       ┌───────────────┐       ┌───────────────┐
│   Test Class  │──────▶│  Page Object  │──────▶│ WebDriver API │
│ (calls methods│       │ (wraps locators│       │ (finds & acts │
│  like login)  │       │  and actions) │       │  on elements) │
└───────────────┘       └───────────────┘       └───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Should page objects contain test assertions or only page interactions? Commit to yes or no.
Common Belief:Page objects should include assertions to check page state.
Tap to reveal reality
Reality:Page objects should only contain methods to interact with the page, not assertions. Assertions belong in test classes.
Why it matters:Mixing assertions into page objects reduces reusability and makes tests harder to maintain.
Quick: Is it okay to hardcode locators directly in test methods? Commit to yes or no.
Common Belief:Hardcoding locators in tests is fine for small projects.
Tap to reveal reality
Reality:Hardcoding locators in tests leads to duplication and fragile tests. Page objects centralize locators for easier updates.
Why it matters:When the UI changes, tests break in many places instead of just one.
Quick: Do you think page objects should manage browser setup and teardown? Commit to yes or no.
Common Belief:Page objects should create and close the WebDriver browser instance.
Tap to reveal reality
Reality:Browser setup and teardown belong in test classes or test frameworks, not page objects.
Why it matters:Separating concerns keeps page objects focused and tests easier to manage.
Quick: Can page objects handle dynamic waits internally? Commit to yes or no.
Common Belief:Tests should handle waits explicitly, not page objects.
Tap to reveal reality
Reality:Page objects should encapsulate waits to hide timing complexity from tests.
Why it matters:This improves test stability and keeps test code clean.
Expert Zone
1
Page objects can be designed to represent not only full pages but also reusable components or widgets, improving modularity.
2
Using method chaining in page objects allows writing fluent and readable test steps, but must be used carefully to avoid confusion.
3
Page objects should avoid exposing raw WebDriver elements to prevent tests from bypassing the abstraction and causing maintenance issues.
When NOT to use
Page objects are less useful for very simple or one-off tests where overhead is not justified. For API testing or non-UI tests, other patterns like service objects or direct calls are better.
Production Patterns
In real projects, page objects are combined with test frameworks like pytest or unittest, use fixtures for setup, and integrate with CI pipelines. They often include logging, error handling, and support for multiple browsers.
Connections
Object-Oriented Programming
Page objects use classes and encapsulation, core OOP principles.
Understanding OOP helps grasp how page objects hide details and expose simple interfaces.
Single Responsibility Principle (SRP)
Page objects follow SRP by having one job: representing a page's UI.
Knowing SRP clarifies why page objects avoid mixing test logic or browser management.
Human Factors in UI Design
Page objects model user interactions, similar to how UI design considers user flows.
Understanding user behavior helps design page object methods that reflect real user actions.
Common Pitfalls
#1Mixing test assertions inside page object methods.
Wrong approach:def login(self, username, password): self.driver.find_element(By.ID, 'user').send_keys(username) self.driver.find_element(By.ID, 'pass').send_keys(password) self.driver.find_element(By.ID, 'login').click() assert 'Welcome' in self.driver.page_source # Wrong: assertion inside page object
Correct approach:def login(self, username, password): self.driver.find_element(By.ID, 'user').send_keys(username) self.driver.find_element(By.ID, 'pass').send_keys(password) self.driver.find_element(By.ID, 'login').click() # Assertion done in test class
Root cause:Confusing responsibilities of page objects and tests leads to fragile and less reusable code.
#2Hardcoding locators in test methods instead of page objects.
Wrong approach:def test_login(driver): driver.get('http://example.com/login') driver.find_element(By.ID, 'user').send_keys('user1') driver.find_element(By.ID, 'pass').send_keys('pass1') driver.find_element(By.ID, 'login').click()
Correct approach:class LoginPage: USER = (By.ID, 'user') PASS = (By.ID, 'pass') LOGIN = (By.ID, 'login') def __init__(self, driver): self.driver = driver def login(self, username, password): self.driver.find_element(*self.USER).send_keys(username) self.driver.find_element(*self.PASS).send_keys(password) self.driver.find_element(*self.LOGIN).click() # Test uses LoginPage.login()
Root cause:Not understanding the benefit of centralizing locators causes duplicated and fragile code.
#3Creating and quitting WebDriver inside page objects.
Wrong approach:class LoginPage: def __init__(self): self.driver = webdriver.Chrome() def close(self): self.driver.quit()
Correct approach:class LoginPage: def __init__(self, driver): self.driver = driver # Test class manages driver lifecycle
Root cause:Mixing concerns of browser management and page representation leads to inflexible design.
Key Takeaways
Page objects separate test logic from page details by encapsulating element locators and interactions in classes.
Keeping assertions in test classes and interactions in page objects improves code clarity and reusability.
Using setup and teardown methods in test classes ensures reliable browser management across tests.
Encapsulating waits and handling dynamic elements inside page objects makes tests more stable.
Advanced page object design uses inheritance and modular components to scale test automation for large projects.