杰瑞科技汇

python page object

Of course! The Page Object Model (POM) is one of the most popular and effective design patterns used in test automation with frameworks like Selenium, Cypress, or Playwright. Let's break it down in Python.

python page object-图1
(图片来源网络,侵删)

What is the Page Object Model?

At its core, POM is a design pattern that creates an Object Repository for your web application's pages. Each page of your application is represented as a class. These classes store the element locators and the methods that perform actions on that page.

The main goal is to abstract away the details of the UI from your test scripts.

Why Use the Page Object Model?

Imagine writing tests without POM:

# Bad Practice - No POM
def test_login():
    driver.get("https://example.com/login")
    driver.find_element(By.ID, "username").send_keys("test_user")
    driver.find_element(By.ID, "password").send_keys("secure_password")
    driver.find_element(By.ID, "submit-btn").click()
    assert "Dashboard" in driver.title

Now, imagine your UI changes. The id of the username field changes from username to user-name. You have to find and update this line in every single test that uses it. This is tedious and error-prone.

python page object-图2
(图片来源网络,侵删)

With POM, this problem is solved.


Core Concepts of POM

  1. Page Object Class: A Python class that represents a page or a component of a web page.

    • Locators: It stores By strategies and locator strings (e.g., By.ID, "username"). These are usually defined as class attributes.
    • Methods: It contains methods that represent user actions on that page (e.g., enter_username(), click_login_button()).
    • No Assertions: The page object class itself should not contain assertions (assert). Its job is to interact with the page, not verify the results. Verification belongs in the test files.
  2. Test Class: A Python class that contains the actual test scripts.

    • It uses the Page Object classes to interact with the application.
    • It contains the assertions to verify the expected outcomes.

Step-by-Step Implementation in Python (with Selenium)

Let's automate a simple login flow using POM.

python page object-图3
(图片来源网络,侵删)

Step 1: Project Structure

A good project structure is key to maintainability.

pom_project/
├── pages/
│   ├── __init__.py
│   ├── login_page.py
│   └── dashboard_page.py
├── tests/
│   ├── __init__.py
│   └── test_login.py
├── utils/
│   └── driver.py
├── config.py
└── requirements.txt

Step 2: Setup and Dependencies

requirements.txt

selenium
pytest

Install them:

pip install -r requirements.txt

Step 3: Create a Base Page (Optional but Recommended)

A BasePage can contain common methods that all page objects can inherit, like finding an element, clicking, etc.

pages/base_page.py

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class BasePage:
    def __init__(self, driver):
        self.driver = driver
    def find_element(self, locator, timeout=10):
        """Finds an element and returns it."""
        return WebDriverWait(self.driver, timeout).until(
            EC.presence_of_element_located(locator)
        )
    def click_element(self, locator):
        """Finds an element and clicks it."""
        element = self.find_element(locator)
        element.click()
    def enter_text(self, locator, text):
        """Finds an element and enters text."""
        element = self.find_element(locator)
        element.clear()
        element.send_keys(text)

Step 4: Create the Page Object for the Login Page

This class will represent the login page. It will have locators and methods specific to that page.

pages/login_page.py

from selenium.webdriver.common.by import By
from .base_page import BasePage
class LoginPage(BasePage):
    # Locators
    USERNAME_INPUT = (By.ID, "username")
    PASSWORD_INPUT = (By.ID, "password")
    LOGIN_BUTTON = (By.ID, "submit-btn")
    ERROR_MESSAGE = (By.ID, "error-message")
    def __init__(self, driver):
        super().__init__(driver)
        self.driver.get("https://the-internet.herokuapp.com/login") # Example URL
    def login(self, username, password):
        """Performs the login action."""
        self.enter_text(self.USERNAME_INPUT, username)
        self.enter_text(self.PASSWORD_INPUT, password)
        self.click_element(self.LOGIN_BUTTON)
    def get_error_message(self):
        """Returns the text of the error message."""
        return self.find_element(self.ERROR_MESSAGE).text

Step 5: Create the Page Object for the Dashboard Page

After a successful login, we land on the dashboard.

pages/dashboard_page.py

from selenium.webdriver.common.by import By
from .base_page import BasePage
class DashboardPage(BasePage):
    # Locators
    LOGOUT_BUTTON = (By.XPATH, "//button[contains(text(), 'Logout')]")
    WELCOME_MESSAGE = (By.ID, "welcome-message")
    def get_welcome_message(self):
        """Returns the text of the welcome message."""
        return self.find_element(self.WELCOME_MESSAGE).text
    def logout(self):
        """Clicks the logout button."""
        self.click_element(self.LOGOUT_BUTTON)

Step 6: Write the Test Script

Now, the test script becomes very clean and readable. It only cares about the "what" (the test steps), not the "how" (the UI locators).

tests/test_login.py

import pytest
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
from pages.login_page import LoginPage
from pages.dashboard_page import DashboardPage
@pytest.fixture
def driver():
    """Fixture to set up and tear down the WebDriver."""
    driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()))
    driver.implicitly_wait(10)
    yield driver
    driver.quit()
def test_successful_login(driver):
    """Test a successful login flow."""
    # Arrange
    login_page = LoginPage(driver)
    dashboard_page = DashboardPage(driver)
    username = "tomsmith"
    password = "SuperSecretPassword!"
    # Act
    login_page.login(username, password)
    # Assert
    # We are now on the dashboard, so we use the dashboard page object
    welcome_text = dashboard_page.get_welcome_message()
    assert "Welcome to the Secure Area" in welcome_text
def test_failed_login(driver):
    """Test a failed login flow."""
    # Arrange
    login_page = LoginPage(driver)
    username = "wrong_user"
    password = "wrong_password"
    # Act
    login_page.login(username, password)
    # Assert
    # We are still on the login page, so we use the login page object
    error_text = login_page.get_error_message()
    assert "Your username is invalid!" in error_text

Running the Tests

Make sure you have pytest installed. You can run your tests from the root directory (pom_project/):

pytest

Benefits of this Approach (Summary)

  • Readability: Tests are like a story: login_page.login(...), dashboard_page.get_welcome_message(). They are easy to understand.
  • Maintainability: If the login button's id changes, you only need to update it in one place: pages/login_page.py. All your tests will continue to work without modification.
  • Reduced Code Duplication: Common actions are encapsulated in methods. If you need to log in from 10 different tests, you call the same login() method.
  • Centralized Locators: All locators are stored in their respective page object files, making them easy to find and manage.
  • Separation of Concerns: The test logic is separate from the UI interaction logic. This makes the codebase cleaner and more robust.

Advanced POM Concepts

  • Page Factory: A built-in Selenium feature that simplifies the initialization of page objects. You use annotations like @FindBy to define locators, and Selenium automatically initializes them.
  • Component Object Model (COM): For very large or complex pages, you can break them down into smaller, reusable components (e.g., a Header component, a Footer component, a SearchBox component). These components are also page objects themselves.
分享:
扫描分享到社交APP
上一篇
下一篇