0
0
Selenium Javatesting~15 mins

Test class consuming page objects in Selenium Java - Deep Dive

Choose your learning style9 modes available
Overview - Test class consuming page objects
What is it?
A test class consuming page objects is a way to write automated tests where the test code uses special helper classes called page objects. These page objects represent parts of a web page and contain methods to interact with them. This approach helps keep test code clean and easy to understand by separating the test logic from the details of how to find and use page elements.
Why it matters
Without using page objects, test code mixes the details of web page structure with test steps, making tests hard to read and maintain. If the web page changes, many tests break and need updates. Using page objects solves this by centralizing page details in one place, so tests stay stable and easier to fix. This saves time and reduces errors in real projects.
Where it fits
Before learning this, you should know basic Selenium commands and how to write simple test scripts. After this, you can learn advanced test design patterns like the Page Factory, test data management, and integrating tests into continuous integration pipelines.
Mental Model
Core Idea
A test class uses page objects as clean, reusable tools to interact with web pages, separating test steps from page details.
Think of it like...
It's like using a remote control to operate a TV instead of pressing buttons directly on the TV itself. The remote (page object) hides the complex buttons and makes it easier to control the TV (web page).
┌───────────────┐       uses       ┌───────────────┐
│  Test Class   │──────────────────▶│ Page Object   │
│ (test steps)  │                   │ (page details)│
└───────────────┘                   └───────────────┘
        │                                  │
        │                                  │
        ▼                                  ▼
  Executes tests                   Finds elements
  and asserts results             and performs actions
Build-Up - 7 Steps
1
FoundationUnderstanding Page Object Basics
🤔
Concept: Page objects represent web pages or parts of them as classes with methods to interact with elements.
A page object class contains locators and methods for buttons, fields, and other elements. For example, a LoginPage class might have methods to enter username, enter password, and click login. This hides the details of locating elements from the test.
Result
You get a reusable class that models a page, making test code simpler and more readable.
Understanding that page objects act as an interface to the page helps keep test code clean and focused on test logic.
2
FoundationWriting a Simple Test Class
🤔
Concept: A test class uses page objects to perform actions and verify results in tests.
In the test class, you create an instance of the page object and call its methods to perform steps. For example, testLogin() calls loginPage.enterUsername(), loginPage.enterPassword(), and loginPage.clickLogin(), then asserts the expected page state.
Result
Tests become easier to write and understand because they use clear, high-level methods from page objects.
Knowing how to use page objects in tests is key to separating test logic from page details.
3
IntermediateUsing Locators with Best Practices
🤔Before reading on: do you think using XPath is always better than CSS selectors? Commit to your answer.
Concept: Choosing good locators in page objects improves test reliability and speed.
Page objects should use stable locators like IDs or CSS selectors instead of brittle XPath. For example, use By.id("username") instead of complex XPath. This reduces test failures when the page changes.
Result
Tests become more stable and faster because locators are efficient and less likely to break.
Understanding locator choice prevents flaky tests and reduces maintenance effort.
4
IntermediateInitializing Page Objects Properly
🤔Before reading on: do you think creating new page object instances inside every test method is best? Commit to your answer.
Concept: Page objects should be initialized once per test or test class to avoid redundant code and improve performance.
Use constructors or setup methods to initialize page objects with the WebDriver instance. For example, in JUnit, use @BeforeEach to create page objects once per test. This avoids repeated code and keeps tests clean.
Result
Tests run efficiently and are easier to maintain because page objects are managed consistently.
Knowing how to initialize page objects properly avoids common setup mistakes and code duplication.
5
IntermediateWriting Assertions in Test Classes
🤔Before reading on: should assertions be inside page objects or test classes? Commit to your answer.
Concept: Assertions belong in test classes, not page objects, to keep responsibilities clear.
Page objects provide methods to get page state, like getTitle() or isErrorDisplayed(). Test classes call these methods and use assertions to verify expected results. This keeps page objects focused on interaction, and tests on validation.
Result
Tests are clearer and easier to debug because validation logic is separate from page interaction.
Understanding separation of concerns improves test design and maintainability.
6
AdvancedHandling Page Navigation Between Objects
🤔Before reading on: do you think page objects should return other page objects after navigation? Commit to your answer.
Concept: Page object methods that cause navigation should return new page object instances representing the new page.
For example, loginPage.clickLogin() returns a HomePage object. This models the real user flow and allows chaining calls in tests. It also keeps tests aware of the current page context.
Result
Tests become more fluent and expressive, reflecting real user journeys.
Knowing to return page objects after navigation models user flow and improves test readability.
7
ExpertAvoiding Common Page Object Anti-Patterns
🤔Before reading on: do you think putting waits and assertions inside page objects is good practice? Commit to your answer.
Concept: Page objects should avoid embedding waits, assertions, or test logic to keep them reusable and simple.
Embedding waits or assertions in page objects mixes concerns and makes them less flexible. Instead, use explicit waits in tests or helper utilities, and keep page objects focused on element interaction. This separation prevents hidden test failures and improves reusability.
Result
Tests are more reliable and easier to maintain because responsibilities are clear and code is modular.
Understanding this separation prevents subtle bugs and keeps page objects clean and reusable.
Under the Hood
Page objects encapsulate Selenium WebDriver calls to find and interact with web elements. When a test calls a page object method, it triggers WebDriver commands like findElement and click behind the scenes. This abstraction hides the complexity of locating elements and performing actions, allowing tests to focus on behavior. The WebDriver manages browser communication, while page objects organize code for maintainability.
Why designed this way?
Page objects were designed to solve the problem of brittle and hard-to-maintain tests caused by mixing page details with test logic. By centralizing element locators and interaction methods, changes to the UI require updates in only one place. This design improves test readability, reduces duplication, and aligns with software engineering principles like separation of concerns and single responsibility.
┌───────────────┐       calls       ┌───────────────┐       uses       ┌───────────────┐
│  Test Class   │──────────────────▶│ Page Object   │──────────────────▶│ WebDriver API │
│ (test logic)  │                   │ (element API) │                   │ (browser)     │
└───────────────┘                   └───────────────┘                   └───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Should page objects contain assertions to verify page state? Commit to yes or no.
Common Belief:Page objects should include assertions to check if elements are visible or correct.
Tap to reveal reality
Reality:Assertions belong in test classes; page objects should only provide methods to interact with or get information from the page.
Why it matters:Mixing assertions into page objects makes them less reusable and harder to maintain, causing confusion about test responsibilities.
Quick: Is it best to create new page object instances inside every test method? Commit to yes or no.
Common Belief:Creating new page object instances in every test method ensures fresh state and is best practice.
Tap to reveal reality
Reality:Page objects should be initialized once per test or test class setup to avoid redundant code and improve performance.
Why it matters:Repeated initialization leads to cluttered code and slower tests, making maintenance harder.
Quick: Are XPath locators always better than CSS selectors? Commit to yes or no.
Common Belief:XPath is more powerful and always the best choice for locating elements.
Tap to reveal reality
Reality:CSS selectors are usually faster and more stable; XPath can be brittle and slower, so CSS is preferred when possible.
Why it matters:Using brittle locators causes flaky tests that fail unexpectedly, wasting time debugging.
Quick: Should waits be embedded inside page object methods? Commit to yes or no.
Common Belief:Embedding waits inside page objects ensures elements are ready before interaction and is good practice.
Tap to reveal reality
Reality:Waits should be handled separately in tests or helper utilities to keep page objects simple and reusable.
Why it matters:Embedding waits hides timing issues and can cause unpredictable test behavior.
Expert Zone
1
Page objects can be designed to return different types based on user roles or page states, enabling flexible test flows.
2
Using interfaces or abstract classes for page objects allows swapping implementations for different browsers or environments without changing tests.
3
Lazy loading elements inside page objects can improve performance but requires careful handling to avoid stale element exceptions.
When NOT to use
Page objects are less suitable for very simple or one-off tests where the overhead is not justified. In such cases, direct WebDriver calls may be simpler. Also, for highly dynamic pages with constantly changing elements, other patterns like Screenplay or UI component models might be better.
Production Patterns
In real projects, page objects are combined with test frameworks like JUnit or TestNG, use dependency injection for WebDriver, and integrate with reporting tools. They often follow layered architecture separating page objects, test logic, and utilities. Fluent interfaces and method chaining are common to write readable tests.
Connections
Object-Oriented Programming
Page objects apply OOP principles like encapsulation and abstraction to testing.
Understanding OOP helps grasp why page objects hide details and expose simple methods, improving code reuse and clarity.
Design Patterns - Facade Pattern
Page objects act as a facade, providing a simple interface to complex page interactions.
Recognizing page objects as a facade clarifies their role in hiding complexity and simplifying test code.
Human-Computer Interaction (HCI)
Page objects model user interactions with the UI, reflecting HCI principles.
Knowing HCI concepts helps design page objects that mimic real user behavior, making tests more realistic.
Common Pitfalls
#1Mixing assertions inside page objects.
Wrong approach:public void verifyLoginSuccess() { Assert.assertTrue(driver.findElement(By.id("welcome")).isDisplayed()); }
Correct approach:public boolean isLoginSuccessful() { return driver.findElement(By.id("welcome")).isDisplayed(); } // Assertion done in test class
Root cause:Confusing responsibilities between page interaction and test validation.
#2Using brittle XPath locators that break easily.
Wrong approach:By userNameField = By.xpath("//div[2]/input[@type='text']");
Correct approach:By userNameField = By.id("username");
Root cause:Not choosing stable, meaningful locators leads to flaky tests.
#3Creating new page object instances inside every test method unnecessarily.
Wrong approach:public void testLogin() { LoginPage loginPage = new LoginPage(driver); /* test steps */ } public void testLogout() { LoginPage loginPage = new LoginPage(driver); /* test steps */ }
Correct approach:@BeforeEach public void setup() { loginPage = new LoginPage(driver); }
Root cause:Lack of understanding of test lifecycle and setup methods.
Key Takeaways
Page objects separate the details of web page structure from test logic, making tests cleaner and easier to maintain.
Test classes use page objects by calling their methods to perform actions and get page state, then assert expected results.
Choosing stable locators and initializing page objects properly prevents flaky tests and redundant code.
Assertions belong in test classes, not page objects, to keep responsibilities clear and code reusable.
Advanced use includes returning page objects after navigation and avoiding embedding waits or assertions inside page objects.