Python Selenium自动化测试:Page Object模式实战解析

小鹿同学
小鹿同学
发布时间:2026-10-13 | 5人浏览过
原创

本文深入剖析Selenium自动化测试中常见的代码混乱问题,并引入Page Object设计模式进行重构。通过对比传统写法与基于BasePage继承的Page模式,详细展示了如何分离页面元素定位与业务逻辑,从而显著提升测试用例的易读性、可扩展性、可复用性及可维护性,帮助开发者构建更稳健的Web自动化测试体系。

Selenium自动化测试的痛点分析

Selenium是目前广泛使用的Web自动化工具,支持Chrome、Firefox、IE等多种浏览器。开发者可以使用Java、C#、Python等熟悉语言编写测试用例,上手门槛较低。然而,在编写完首个自动化用例后,虽然初期可能感到兴奋,但审视代码结构时往往会发现逻辑杂乱无章,例如大量重复的find element调用,导致代码难以阅读。


__author__ = 'xua'

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import unittest

class TCRepeatLogin(unittest.TestCase):
  def setUp(self):

    #webdriver
    self.driver = webdriver.Chrome(r'C:\Users\xua\Downloads\chromedriver_win32\chromedriver.exe')
    self.driver.implicitly_wait(30)
    self.base_url = "http://10.222.30.145:9000/"

  def test_(self):
    driver = self.driver
    driver.get(self.base_url)

    #enter username and password
    driver.find_element_by_id("username").clear()
    driver.find_element_by_id("username").send_keys("sbxadmin")
    driver.find_element_by_id("password").clear()
    driver.find_element_by_id("password").send_keys("IGTtest1"+Keys.RETURN)

    #find dialog and check
    dialogTitle = driver.find_element(By.XPATH,'//html/body/div[7]/div/div/div[1]/h3')
    self.assertEqual("Sign in",dialogTitle.text)

    #find cancel button and click
    cancelBtn = driver.find_element(By.XPATH,'//html/body/div[7]/div/div/div[3]/button[2]')
    cancelBtn.click()

  def tearDown(self):
    self.driver.close()

if __name__ == "__main__":
  unittest.main()

针对上述代码结构,我们可以从以下几个维度进行深入分析:

1. 易读性差:代码难以理解,充斥着大量的find element调用,无法直观体现测试用例的逻辑意图。

2. 可扩展性弱:各个测试用例相互孤立,缺乏统一的架构支持,难以进行功能扩展。

3. 可复用性低:缺乏公共方法封装,导致代码片段难以在不同测试场景中复用。

4. 可维护性差:一旦页面元素发生变化,必须逐一修改所有相关的测试用例,维护工作量巨大。

Page Object模式架构设计

为解决上述问题,Python中引入了Page Object模式来管理测试逻辑。其基本架构如示意图所示(注:原图箭头示意TestCase指向各个Page类,因软件限制未作修改):

Page模式的核心设计原则如下:

1. 定义一个BasePage基类,该类包含指向Selenium WebDriver的实例属性,作为所有页面类的父类。

2. 每个具体的Web页面类继承自BasePage,通过driver获取页面元素,并将针对该页面的所有操作抽象为独立的方法。

3. 测试用例类(TestCase)继承自unittest.TestCase,并依赖具体的Page类来执行相应的测试步骤,实现逻辑与数据的分离。

利用Page模式重构后的代码如下:

BasePage.py实现:


__author__ = 'xua'

from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys


#super class
class BasePage(object):
  def __init__(self, driver):
    self.driver = driver


class LoginPage(BasePage):
  
  #page element identifier
  usename = (By.ID,'username')
  password = (By.ID, 'password')
  dialogTitle = (By.XPATH,'//html/body/div[7]/div/div/div[1]/h3')
  cancelButton = (By.XPATH,'//html/body/div[7]/div/div/div[3]/button[2]')

  #Get username textbox and input username
  def set_username(self,username):
    name = self.driver.find_element(*LoginPage.usename)
    name.send_keys(username)
  
  #Get password textbox and input password, then hit return
  def set_password(self, password):
    pwd = self.driver.find_element(*LoginPage.password)
    pwd.send_keys(password + Keys.RETURN)

  #Get pop up dialog title
  def get_DiaglogTitle(self):
    digTitle = self.driver.find_element(*LoginPage.dialogTitle)
    return digTitle.text

  #Get "cancel" button and then click
  def click_cancel(self):
    cancelbtn = self.driver.find_element(*LoginPage.cancelButton)
    cancelbtn.click()

Test_Login.py实现:


__author__ = 'xua'

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.alert import Alert
import unittest
import time
import BasePage

class Test_Login(unittest.TestCase):

  #Setup
  def setUp(self):
    self.driver = webdriver.Chrome(r'C:\Users\xua\Downloads\chromedriver_win32\chromedriver.exe')
    self.driver.implicitly_wait(30)
    self.base_url = "http://10.222.30.145:9000/"
  #tearDown
  def tearDown(self):
    self.driver.close()

  def test_Login(self):
    #Step1: open base site
    self.driver.get(self.base_url)
    #Step2: Open Login page
    login_page = BasePage.LoginPage(self.driver)
    #Step3: Enter username
    login_page.set_username("sbXadmin")
    #Step4: Enter password
    login_page.set_password("IGTtest1")
    #Checkpoint1: Check popup dialog title
    self.assertEqual(login_page.get_DiaglogTitle(),"Sign in")
    #Step5: Cancel dialog
    login_page.click_cancel()


if __name__ == "__main__":
  unittest.main()

Page模式优势验证

回顾重构后的代码,Page模式是否有效解决了前述四个方面的问题?

1. 易读性:观察test_login方法,逻辑清晰,每一步操作明确,符合测试用例的阅读习惯。

2. 可扩展性:由于每个页面的元素操作都封装在对应的Page类中,新增、删除或修改功能变得非常便捷。

3. 可复用性:Page中的基础操作被封装为方法,可以在不同的测试用例中重复调用,避免代码冗余。

4. 可维护性:若页面元素发生变更,只需修改对应Page类中的方法即可,无需改动具体的测试用例代码。

总结:

Page模式提供了一种优秀的页面逻辑与测试用例分离机制,有效降低了模块间的耦合度,提高了代码的内聚性,使Web自动化测试更加灵活高效。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表