🧾 一、项目背景
在自动化测试中,页面对象模型(Page Object Model) 是一种非常重要的设计模式,它将页面元素和操作封装成类,提升代码复用性、可维护性和可读性。
本文将以一个完整的 BasePage 页面基类 实现为例,详细讲解如何构建一个结构清晰、功能强大的 Selenium 页面基类,并结合日志记录、截图、等待等常用功能进行二次封装,为后续编写测试用例打下坚实基础。
🧱 二、项目结构概览
Auto_selenium/
├── page_objects/
│ └── base_page.py # 页面基类
├── utils/
│ └── logger.py # 日志工具类
├── test_cases/ # 测试用例目录
└── run_all_tests.py # 测试执行入口
我们将在 base_page.py 中实现一个通用的 BasePage 类,供所有页面继承使用。
🛠️ 三、BasePage 类详解
1. 初始化方法
def __init__(self, driver):
self.driver = driver
- 构造函数接收浏览器驱动作为参数,每个页面对象都将拥有对浏览器的访问能力。
- 这是 Page Object 模式的基础。
2. 打开网页
def open(self, url):
self.driver.get(url)
- 封装 get() 方法,用于打开指定 URL。
- 示例调用:
page.open("https://www.baidu.com")
3. 浏览器前进与后退
def forward(self):
self.driver.forward()
logger.info("在当前页面上单击前进......")
def back(self):
self.driver.back()
logger.info("点击返回当前页面......")
- 控制浏览器前进、后退操作。
- 结合日志输出,便于调试和报告生成。
4. 显式等待
def wait(self, loc, seconds):
try:
wait_ = WebDriverWait(self.driver, seconds)
wait_.until(lambda driver: driver.find_element(*loc))
logger.info("等待 %d 秒......" % seconds)
except NameError as e:
logger.error("未能加载元素 %s" % e)
- 使用 WebDriverWait 等待元素出现,避免因元素未加载完成导致查找失败。
- 推荐替代 time.sleep(),提高脚本健壮性。
5. 截图功能
def get_browser_img(self, timestamp=None):
"""
截图并保存到项目根目录下的 screenshots 文件夹中。
:param timestamp: 可选参数,用于指定截图文件名的时间戳
"""
try:
base_dir = os.path.dirname(os.path.abspath('__file__')) # 项目根目录
screenshot_dir = os.path.join(base_dir, 'screenshots')
# 自动创建目录(如果不存在)
os.makedirs(screenshot_dir, exist_ok=True)
# 如果未提供 timestamp,则使用当前时间
if timestamp is None:
timestamp = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
# 构建文件路径
screen_name = os.path.join(screenshot_dir, f"{timestamp}.png")
# 执行截图并保存
self.driver.get_screenshot_as_file(screen_name)
logger.info("已截图并保存到文件夹 : /screenshots")
except Exception as e:
logger.error("截图失败! %s" % e)
self.get_browser_img(timestamp) # 递归调用,重新截图
- 自动创建 screenshots 文件夹。
- 支持自定义时间戳命名文件。
- 出错时自动截图并递归重试。
✅ 建议:可在测试失败时自动调用该方法,辅助定位问题。
6. 元素定位与操作
定位元素
def find_element(self, loc):
return self.driver.find_element(*loc)
- 返回一个 WebElement 对象,支持多种定位方式 (By.ID, 'id')。
输入文本
def send_keys(self, selector, text):
el = self.find_element(selector)
el.clear()
try:
el.send_keys(text)
logger.info("在输入框中输入 \' %s \' " % text)
except NameError as e:
logger.error("在输入框中选择 %s 失败" % e)
self.get_browser_img()
- 清空输入框后输入内容。
- 异常处理+截图机制,确保稳定性。
清除文本
def clear(self, selector):
el = self.find_element(selector)
try:
el.clear()
logger.info("输入前清除输入框中的文本......")
except NameError as e:
logger.error("Failed to clear in input box with %s" % e)
self.get_browser_img()
- 防止旧数据干扰新操作。
点击元素
def click(self, selector):
el = self.find_element(selector)
try:
el.click()
logger.info("点击元素 \'%s\' " % el.text)
except NameError as e:
logger.error("Failed to click the element with %s" % e)
self.get_browser_img()
- 可记录点击的文本信息,方便日志分析。
7. 鼠标操作(悬停+点击)
def move_element(self, loc, sloc):
mouse = self.find_element(loc)
try:
ActionChains(self.driver).move_to_element(mouse).perform()
self.click(sloc)
except Exception as e:
logger.error("Failed to click move_element with %s" % e)
self.get_browser_img()
- 适用于菜单、下拉框等需要鼠标悬停才能点击的场景。
- 支持链式操作 + 错误处理。
8. 强制等待(静态方法)
@staticmethod
def sleep(seconds):
time.sleep(seconds)
logger.info("强制等 %d 秒" % seconds)
- 使用 @staticmethod 装饰器,不依赖实例或类。
- 适合全局使用的工具方法。
📦 四、如何在实际测试中使用?
示例:百度搜索页面类
from page_objects.base_page import BasePage
class BaiduSearchPage(BasePage):
def search(self, keyword):
self.send_keys(("id", "kw"), keyword)
self.click(("id", "su"))
示例:测试用例调用
from selenium import webdriver
from page_objects.baidu_search_page import BaiduSearchPage
driver = webdriver.Chrome()
page = BaiduSearchPage(driver)
page.open("https://www.baidu.com")
page.search("Selenium")
📝 五、总结
该 BasePage 页面基类为 Selenium 自动化测试提供了良好的封装基础,包含了浏览器操作、元素定位、等待机制、截图功能及日志记录等常用操作。通过继承该基类,可提升测试代码的复用性与可维护性,同时结合异常处理和工具方法,增强了脚本的稳定性与可读性,是构建高效自动化测试框架的重要组成部分。