最近,我在项目中遇到了一个典型的多级审批场景:复杂业务申请流程。这个流程需要经过申请人发起、资源协调岗确认、业务部门审核、相关职能部门(如职能部门A、职能部门B)会签、分管领导审批、主要领导审批等长达 5-7 个环节。为了从繁琐的登录-切换-填表循环中解脱出来,我开发了一个基于 Python + Playwright 的自动化测试脚本,极大地提升了测试效率。
今天,我想分享一下这个工具的设计思路和关键技术点,特别是针对 老旧系统(Legacy System) 的一些自动化技巧。
在选择自动化工具时,我主要考虑了以下几点:
BrowserContext 能够完美实现 Session 隔离,就像开了多个隐身窗口一样。这是整个脚本最核心的部分。传统的测试方法可能需要开启多个浏览器实例,或者频繁注销登录。而使用 Playwright,我们可以为每个用户创建一个独立的 context。
# 为每个用户创建一个独立的上下文(BrowserContext),实现会话隔离context = browser.new_context()contexts.append(context)# 在该上下文中创建页面并登录page = context.new_page()# ... 执行登录逻辑 ...这样,脚本可以一次性启动并将所有相关人员(申请人、各级审批人)全部登录完毕,每个窗口对应一个用户,互不干扰。
很多存量系统仍在使用 <frameset> 布局,菜单和内容分布在不同的 Frame 中。直接查找元素往往会失败,因为元素在特定的 Frame 上下文中。
我封装了一个通用函数来定位 Frame,并增加了对菜单折叠状态的智能判断:
def get_frame_by_url_part(page, url_part): for frame in page.frames: if url_part in frame.url: return frame return None# 智能展开菜单逻辑bar_frame = get_frame_by_url_part(page, "frameLeftBar.html")# 获取隐藏域的值判断菜单状态status = bar_frame.locator("#menu_status").input_value()if status == "close": print("菜单栏处于隐藏状态,正在展开...") bar_frame.click("#toggle_btn")在自动化填写表单时,我遇到了一些棘手的问题,比如前端框架(EasyUI/Layui)对原生 HTML 控件的封装和隐藏。
很多前端日期控件是只读的,不允许直接输入。我使用了 JS 注入的方式直接修改 DOM 元素的值,并手动触发事件:
# 使用 JS 直接赋值日期字段,避免日历控件交互问题js_set_date = """ (el, value) => { if(el) { el.value = value; // 模拟用户输入后的关键事件,确保前端框架能感知到数据变化 el.dispatchEvent(new Event('input')); el.dispatchEvent(new Event('change')); el.dispatchEvent(new Event('blur')); } }"""page.locator("#startTime").evaluate(js_set_date, "2026-05-01")Layui 等框架的文件输入框通常是隐藏的。使用 Playwright 的 set_input_files 方法可以直接定位到底层的 input 元素:
# 定位隐藏的文件输入框file_path = os.path.abspath("tests/test_file.txt")page.locator(".layui-upload-file").set_input_files(file_path)在自动化测试中,脚本执行速度往往远快于人工。在处理 EasyUI 的 Dialog 弹窗时,我遇到了 MissingServletRequestParameterException 异常。
原因分析:脚本在弹窗出现的瞬间就点击了“同意”按钮,但此时弹窗内的隐藏域(如 applyId)尚未通过 AJAX 加载完成,导致提交的请求参数缺失。
解决方案:在关键操作前增加显式等待,或等待特定数据元素出现。
# 等待审批弹窗出现agree_btn = frame.locator(".dialog-button .l-btn:has-text('同意')")agree_btn.wait_for(state="visible")# 【关键】增加缓冲时间,确保弹窗内的 form 数据(如 hidden input)加载完毕print("等待弹窗内容加载...")page.wait_for_timeout(2000) agree_btn.click()此外,脚本还实现了自动检测并关闭“操作成功”提示框的功能,实现了真正的全流程无人值守。
为了应对不同的审批路径(如互审、单审、双审),我将测试场景抽象为配置项。脚本会根据列表顺序,自动判断第一个用户为“申请人”,后续用户为“审批人”。
# 流程角色配置(脱敏示例)SCHEDULING_REVIEWER = "USER_RESOURCE" # 资源协调DEPT_REVIEWERS = ["USER_DEPT_A", "USER_DEPT_B"] # 业务部门FUNC_REVIEWERS = ["USER_FUNC_A", "USER_FUNC_B", "USER_LEADER"] # 职能部门及领导SCENARIOS = { "1": { "name": "场景 A:标准互审流程", # 顺序:申请人 -> 资源协调 -> 业务部门 -> 职能部门 -> 领导 "user_ids": ["USER_APP"] + [SCHEDULING_REVIEWER] + DEPT_REVIEWERS + FUNC_REVIEWERS, "applicant_id": "USER_APP", }, # ... 其他场景}通过这个脚本,原本需要人工操作 10-15 分钟的完整审批流程验证,现在只需要 30秒 左右即可完成所有角色的登录、申请提交及全链路审批。
这不仅节省了大量时间,更重要的是它让测试变得可重复、低成本。每次代码更新后,我都可以快速跑一遍核心场景,确保没有引入回归 BUG。
如果你也在被繁琐的业务流程测试所困扰,强烈建议尝试一下 Playwright。它不仅是自动化的工具,更是提升开发幸福感的神器!