Bird
Raised Fist0
Selenium Pythontesting~15 mins

Test class using page objects in Selenium Python - Deep Dive

Choose your learning style10 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.

Practice

(1/5)
1. What is the main purpose of using a page object in Selenium test classes?
easy
A. To separate page details from test logic for easier maintenance
B. To write all test steps inside the test class directly
C. To avoid using locators in tests
D. To run tests faster by skipping page loading

Solution

  1. Step 1: Understand page object role

    Page objects hold locators and page actions, separating them from test logic.
  2. Step 2: Recognize test class role

    Test classes use page objects to perform actions and assertions, improving readability and maintenance.
  3. Final Answer:

    To separate page details from test logic for easier maintenance -> Option A
  4. Quick Check:

    Page objects separate page details = C [OK]
Hint: Page objects keep page info separate from tests [OK]
Common Mistakes:
  • Thinking tests should contain locators directly
  • Believing page objects speed up test execution
  • Confusing page objects with test runners
2. Which of the following is the correct way to define a page object class in Python using Selenium?
easy
A. class LoginPage: def __init__(self): self.username_input = driver.find_element(By.ID, 'username')
B. def LoginPage(driver): username_input = driver.find_element(By.ID, 'username')
C. class LoginPage: def __init__(self, driver): self.driver = driver self.username_input = driver.find_element(By.ID, 'username')
D. class LoginPage: def __init__(self, driver): self.username_input = driver.find_element('username')

Solution

  1. 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.
  2. 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.
  3. Final Answer:

    Correct page object class with driver parameter and locator using By.ID -> Option C
  4. Quick Check:

    Class with __init__(driver) and By.ID locator = A [OK]
Hint: Page object classes need __init__(self, driver) and proper locators [OK]
Common Mistakes:
  • Missing driver parameter in __init__
  • Using driver.find_element without By selector
  • Defining page object as a function instead of class
3. Given the following test class using a page object, what will be printed if the username input is found and the page title is 'Login Page'?
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'
medium
A. None
B. Login Page
C. driver.title
D. Error: driver not defined

Solution

  1. Step 1: Understand get_title method

    get_title returns driver.title, which is 'Login Page' as given.
  2. Step 2: Check test_title method output

    test_title creates LoginPage instance and prints get_title result, so it prints 'Login Page'.
  3. Final Answer:

    Login Page -> Option B
  4. Quick Check:

    page.get_title() returns 'Login Page' [OK]
Hint: get_title returns driver.title, prints page title string [OK]
Common Mistakes:
  • Confusing method return with attribute name
  • Assuming print outputs None
  • Thinking driver is undefined inside test method
4. Identify the error in this test class using a page object:
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')
medium
A. LoginPage is instantiated without driver argument
B. send_keys method is called incorrectly
C. By.ID locator is invalid
D. test_enter_username method missing self parameter

Solution

  1. Step 1: Check LoginPage instantiation

    LoginPage requires driver argument in __init__, but called without arguments in test_enter_username.
  2. 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.
  3. Final Answer:

    LoginPage is instantiated without driver argument -> Option A
  4. Quick Check:

    Missing driver argument in LoginPage() call = B [OK]
Hint: Check constructor arguments when creating page object instances [OK]
Common Mistakes:
  • Forgetting to pass driver to page object constructor
  • Assuming send_keys needs different syntax
  • Confusing locator syntax errors
5. You want to write a test class that uses a page object to check if a login button is visible and clickable. Which approach correctly combines page object and test class methods?
hard
A. Test class calls page object method that returns the button WebElement but does not check visibility
B. Test class directly uses driver.find_element to check button visibility, ignoring page object
C. Page object only stores locators; test class performs all actions and assertions
D. Page object has method is_login_button_clickable() returning True/False; test class asserts this method's result

Solution

  1. Step 1: Understand page object responsibility

    Page objects should provide methods that check element states like visibility and clickability.
  2. Step 2: Understand test class responsibility

    Test class uses page object methods to assert expected conditions, keeping test logic separate from page details.
  3. Final Answer:

    Page object has method is_login_button_clickable() returning True/False; test class asserts this method's result -> Option D
  4. Quick Check:

    Page object checks state, test asserts result = D [OK]
Hint: Page object checks element state; test asserts result [OK]
Common Mistakes:
  • Mixing locator logic inside test class
  • Not returning boolean from page object methods
  • Ignoring visibility checks in tests
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