若依 RuoYi-Vue 后台管理系统 UI 自动化测试框架 —— 基于 Selenium + Pytest + POM 分层架构实战
前言
做过 Web UI 自动化测试的小伙伴应该都深有体会 —— 脚本写起来容易,维护起来是真难。页面一改版,元素的 XPath 满天飞;用例一多,重复代码堆积成山;跑完测试只有冷冰冰的控制台日志,出了问题连个截图都没有。
最近针对若依 RuoYi-Vue 后台管理系统搭建了一套企业级的 UI 自动化测试框架,把这些问题都解决了。本文将完整介绍这套框架的设计思路和实现细节,希望能给大家一些参考。
一、项目概述
本项目的测试目标系统为若依官方演示站:https://demo.ruoyi.vip/login。
框架采用经典的 POM(Page Object Model)三层分层架构,结合 pytest 强大的 fixture 和参数化能力,构建出一套可维护、可复用、可扩展的自动化测试工程。当前已实现的核心测试场景包括:
- 登录模块自动化测试
- 用户管理模块的条件查询测试(Excel 数据驱动)
二、技术栈一览
| 技术 | 版本 | 用途 |
|---|---|---|
| Python | 3.12+ | 主力编程语言 |
| Selenium | 4.0+ | Web UI 自动化驱动 |
| pytest | 8.0+ | 测试用例管理、fixture、参数化 |
| pandas | — | Excel 测试数据读取 |
| Allure | 2.0+ | 可视化测试报告生成 |
| Ruff | — | 代码质量检查与格式化 |
| Edge WebDriver | — | 浏览器驱动(Microsoft Edge) |
三、项目结构 —— POM 三层分层
这是整个框架最核心的部分。目录结构如下:
web_framwork/
├── bases/ # 【基础封装层】
│ └── base_page.py # 封装通用浏览器操作
│
├── poms/ # 【页面对象层】
│ ├── login_page.py # 登录页 PO
│ └── user_list.py # 用户列表页 PO
│
├── testcases/ # 【测试用例层】
│ ├── test_ruoyi.py # 核心测试用例
│ └── select_user.xlsx # Excel 测试数据
│
├── commons/ # 【工具层】
│ └── excel_utils.py # Excel 数据读取工具
│
├── conftest.py # pytest 全局 fixture
├── main.py # 入口脚本
├── pytest.ini # pytest 配置
└── requirements.txt # 依赖清单
3.1 基础封装层(bases)
文件:
bases/base_page.py
这一层对 Selenium 原生 API 进行了二次封装,是整个框架的基石。主要做了以下增强:
- 统一等待机制:内置了10秒的显式等待,解决页面加载速度不稳定导致的元素定位失败
- 失败自动截图:定位失败时自动调用
save_screenshot(),保存到files/目录 - Allure 报告集成:截图通过
allure.attach()嵌入测试报告 - iframe 切换封装:若依的页面大量使用 iframe,这里封装了多级菜单点击 + iframe 切换的操作
核心代码骨架:
class BasePage:
def find_ele(self, loc: str, timeout=10):
"""单元素定位,失败自动截图并上传Allure"""
try:
return WebDriverWait(self.driver, timeout).until(
EC.presence_of_element_located((By.XPATH, loc))
)
except TimeoutException:
# 失败截图并附加到 Allure 报告
self._take_screenshot_and_attach()
raise
def goto_frame(self, menu_xpath: str, frame_src: str):
"""点击侧边栏菜单 + 切换到目标 iframe"""
self.find_ele(menu_xpath).click()
self.driver.switch_to.frame(self.find_ele_by_attribute('src', frame_src))
3.2 页面对象层(poms)
文件:
poms/login_page.py、poms/user_list.py
按页面维度管理元素定位和页面操作,不包含任何测试断言。以用户列表页为例:
class UserListPage(BasePage):
# --- 元素定位 ---
search_login_name = '//input[@placeholder="登录名称"]'
search_phone = '//input[@placeholder="手机号码"]'
select_status = '//select[@name="status"]'
btn_search = '//button[contains(.,"查询")]'
# --- 页面操作 ---
def switch_to_user_list(self):
"""通过侧边栏进入用户管理页面"""
self.goto_frame('//span[text()="用户管理"]', '/system/user')
def input_login_name(self, name: str):
if pd.notna(name):
self.find_ele(self.search_login_name).send_keys(name)
def select_status_value(self, status):
if pd.notna(status):
Select(self.find_ele(self.select_status)).select_by_value(status)
def click_search(self):
self.find_ele(self.btn_search).click()
当页面元素变化时,只需修改这一层的 XPath,测试用例完全不受影响。
3.3 测试用例层(testcases)
文件:
testcases/test_ruoyi.py
纯粹的测试逻辑,配合 Allure 装饰器构建层级化报告:
@allure.epic("若依后台管理系统")
@allure.feature("用户管理")
class TestRuoyi:
@allure.story("用户查询")
@allure.title("条件查询用户 - {loginName}/{phonenumber}/{status}")
@pytest.mark.parametrize("test_data", load_excel_data("select_user.xlsx", "select_user"))
@pytest.mark.smoke
def test_select_user(self, all_case_fixture, test_data):
"""Excel 数据驱动:多种条件组合查询用户"""
driver = all_case_fixture
user_page = UserListPage(driver)
user_page.switch_to_user_list()
user_page.input_login_name(test_data["loginName"])
user_page.input_phone(test_data["phonenumber"])
user_page.select_status_value(test_data["status"])
user_page.click_search()
# 验证搜索结果
result = user_page.get_search_result()
assert len(result) > 0, "查询结果不能为空"
四、核心特性详解
4.1 登录 Session 复用(Fixture 机制)
文件:
conftest.py
每次跑用例都要重新登录是很大的浪费。通过 pytest 的 fixture 机制,在 conftest.py 中定义了全局 fixture:
@pytest.fixture(scope="function")
def all_case_fixture(request):
driver = webdriver.Edge()
driver.get("https://demo.ruoyi.vip/login")
# 手动输入验证码(绕过验证码识别)
verify_code = input("请输入验证码:")
LoginPage(driver).login(username="admin", password="admin123", code=verify_code)
yield driver
driver.quit()
由于若依的验证码无法自动识别,这里巧妙地采用了控制台交互输入验证码的方式,简单实用。
4.2 Excel 数据驱动
文件:
commons/excel_utils.py+testcases/select_user.xlsx
用 Excel 管理测试数据,测试人员无需懂代码也能维护:
| loginName | phonenumber | status |
|---|---|---|
| admin | 13888888888 | 0 |
| (空) | 13999999999 | 1 |
| test | (空) | (空) |
def load_excel_data(file_path: str, sheet_name: str) -> list[dict]:
df = pd.read_excel(file_path, sheet_name=sheet_name, dtype=str)
return df.to_dict(orient="records")
通过 @pytest.mark.parametrize 将 Excel 数据注入测试用例,一条用例覆盖 N 组数据,大大减少重复代码。
4.3 Allure 可视化测试报告
在 pytest.ini 中统一配置 Allure 参数:
[pytest]
addopts = -s -v --alluredir=temps --clean-alluredir
运行 python main.py 后自动生成报告:
allure generate temps -o report -c
allure open report
报告中可以看到史诗 → 功能 → 用户故事的层级结构,失败用例附带截图,执行耗时一目了然。
4.4 日志与异常处理
框架全程使用 Python 标准库 logging,关键节点都有日志输出。元素定位失败时不仅截图留证,还会在报告中标记失败原因。
五、快速上手
环境准备
# 1. 克隆项目
git clone https://github.com/S1yexX/Ruoyi-selenium-ui-autotest.git
cd web_framwork
# 2. 创建虚拟环境
python -m venv .venv
.venv\Scripts\activate # Windows
source .venv/bin/activate # Mac/Linux
# 3. 安装依赖
pip install -r requirements.txt
# 4. 安装 Allure 命令行工具
# Windows: scoop install allure
# Mac: brew install allure
# Linux: 下载 allure-commandline 并配置 PATH
运行测试
# 运行全部用例
pytest testcases/ -v
# 仅运行冒烟测试
pytest testcases/ -v -m smoke
# 运行并自动生成 Allure 报告
python main.py
⚠️ 注意:运行时控制台会提示输入验证码,请打开浏览器中的若依登录页,查看验证码并输入。
六、项目亮点总结
- 标准化 POM 三层架构 —— 元素定位、页面操作、测试逻辑彻底解耦,修改页面不影响用例
- 二次封装 Selenium —— 统一等待 + 失败截图 + Allure 集成,告别 flaky 测试
- Excel 数据驱动 —— 测试数据与代码分离,非技术人员也能维护
- Allure 可视化报告 —— 层级化展示,失败截图嵌入,一目了然
- Fixture 会话复用 —— 避免重复登录,提升用例执行效率
- 工程化规范 —— pytest.ini + ruff.toml + pyproject.toml 三件套,保证代码质量
七、后续计划
目前框架已实现用户管理模块的查询功能自动化,后续计划扩展:
- 用户新增 / 编辑 / 删除功能自动化
- 更多模块覆盖(角色管理、菜单管理、日志管理等)
- CI/CD 集成(GitHub Actions 自动执行 + Allure 报告发布)
- 验证码自动识别(OCR 方案)
- Docker 化运行环境
八、总结
这套框架虽然规模不大,但五脏俱全 —— POM 分层、数据驱动、fixture、Allure 报告、代码规范,每一个点都是企业级自动化测试的标配能力。如果你也在做若依项目的二次开发或者想学习 Selenium + pytest 的实战用法,相信这个项目会对你有所帮助。
欢迎 Star ⭐ 和 PR,一起交流进步!
📌 项目地址
- GitHub:https://github.com/S1yexX/Ruoyi-selenium-ui-autotest
- Gitee:https://gitee.com/thousand-rows/ruoyi-selenium-ui-autotest
更多推荐



所有评论(0)