PlayPilot:基于 Playwright 的 UI 自动化调试平台
项目: 基于 Playwright pytest 的 Web UI 自动化测试框架项目描述: 本项目是一个基于 Playwright pytest 的 Web UI 自动化测试框架用于测试测试管理平台的 Web 端功能。文档版本: v1.0编写日期: 2026-05-201. 文档概述1.1 编写目的本文档用于指导基于本框架进行的 Web UI 自动化测试用例的设计、组织与实施。明确测试范围、设计原则、用例分层结构、覆盖矩阵、断言策略与执行计划,为测试人员提供统一的设计依据。1.2 适用范围框架范围: 当前目录playwright-ui下的 Playwright pytest 自动化测试工程被测对象: 测试管理平台 Web 端 (登录、注册、项目管理、模块管理、环境管理等)读者对象: QA 测试工程师、测试负责人、开发对接人1.3 名词与缩写缩写/术语含义POMPage Object Model 页面对象模式Mock通过page.route拦截并伪造接口响应Allure测试报告框架,生成可视化 HTML 报告TracePlaywright 提供的执行轨迹文件,可在线回放Fixturepytest 的依赖注入机制,用于初始化/销毁测试上下文2. 测试框架与项目结构2.1 技术栈测试运行器: pytest浏览器自动化: Playwright (Python 同步 API)报告: Allure (./reports→./allure_report)失败诊断: Tracing (retain-on-failure)、截图、视频多浏览器: Chromium / Firefox / WebKit依赖管理:requirements.txt2.2 目录结构与职责playwright-ui/ ├── cases/ 测试用例集 (test_*.py) │ ├── conftest.py 登录、未登录上下文等 fixture │ ├── test_login.py 登录功能用例 │ ├── test_register.py 注册功能用例 │ ├── test_project_list.py 项目列表用例 │ ├── test_add_project.py 添加项目用例 │ ├── test_add_module.py 添加模块用例 │ ├── test_env_list.py 环境列表用例 │ └── more_accounts/ 多账号协同场景 ├── pages/ Page Object 封装 (元素定位 操作) ├── mocks/mock_api.py 接口 Mock 数据 ├── plugins/ pytest 自定义插件 ├── conftest.py 根级 fixture (浏览器启动参数) ├── pytest.ini 运行配置 (base-url、tracing、screenshot) └── run.py 入口,运行 生成 Allure 报告2.3 全局运行配置 (pytest.ini)参数取值说明--base-urlhttp://47.116.12.183被测环境地址--headed启用显示浏览器窗口便于调试--tracingretain-on-failure失败保留 trace--screenshotonly-on-failure失败截图--videoretain-on-failure失败保留视频log_cli_levelinfo命令行实时输出日志3. 测试范围与目标3.1 测试目标验证被测系统核心业务流的功能正确性 (登录、注册、项目/模块/环境的增查改删)验证表单输入校验、错误提示、按钮可用状态等 UI 交互逻辑通过接口 Mock 覆盖各类异常分支 (400/403/500、网络异常、重复数据)验证页面跳转、URL、Title 等导航行为通过持续集成保障核心链路回归质量3.2 测试范围在范围内登录、注册页面表单校验与登录注册主流程项目列表 (新增、搜索、刷新、行内编辑、行内删除)添加项目页 (字段校验、保存成功、重复、服务器异常)添加模块页 (模块名、所属项目、保存、重复)环境列表 (新增环境、名称/地址校验、重复、保存成功)多账号并发场景 (A 账号新建, B 账号删除)接口请求与响应捕获、Cookie 隔离、Mock 数据不在范围内服务端单元/接口级别测试 (由 API 测试团队负责)浏览器兼容性 IE 系列 (Playwright 不支持)性能/压力测试、安全测试移动端原生 APP 测试3.3 质量目标维度目标值核心用例覆盖率≥ 95% (登录/注册/项目/模块/环境主流程)用例稳定通过率≥ 98% (连续 5 次运行)用例平均耗时≤ 8s/case失败用例诊断时长≤ 5 分钟 (借助 trace 视频)4. 测试策略4.1 分层与隔离登录态隔离:需登录用例: 使用login_first(session 级) 默认pagefixture,复用登录态不需登录用例 (登录/注册页): 使用unlogin_context(module 级) unlogin_page(function 级),保证无 cookie多账号场景: 使用admin_context创建独立上下文Page Object 分层: 元素定位与操作封装在pages/,用例只调用业务方法,不出现裸 selector4.2 数据策略数据类型策略示例静态账号共用账号py / 123456登录、登录态前置动态唯一数据uuid.uuid4()[:8]注册成功用例的用户名、新增项目名Mock 数据mocks/mock_api.py集中维护重复名称、403 无权限、500 异常边界数据参数化pytest.mark.parametrize30 字符上下边界、特殊字符4.3 等价类与边界值划分原则对每个输入字段,均按以下维度设计用例:维度必含用例必填空值校验长度最小值-1、最小值、最大值、最大值1字符集中文、英文、数字、特殊字符、空格、混合唯一性已存在/不存在业务规则例如环境地址必须http://或https://开头4.4 断言策略优先使用 Playwright 内置自动等待断言expect(locator).to_xxx(),避免time.sleep:可见性:to_be_visible()/not_to_be_visible()文本:to_contain_text()/to_have_text()属性:to_have_attribute()、to_have_value()按钮状态:to_be_enabled()/to_be_disabled()导航:to_have_url()/to_have_title()/page.expect_navigation请求/响应:page.expect_request()/page.expect_response()校验请求方法、URL、body、status4.5 Mock 使用准则何时 Mock: 异常分支 (400/403/500)、不可重复构造的数据 (重复名称)、列表为 0/1 条结果的边界场景何时不 Mock: 主流程 happy path 必须打真实接口,确保端到端可用Mock 维护: 统一收敛在mocks/mock_api.py,命名格式mock_resource_status5. 测试用例设计编号规则:TC-模块-序号,例如TC-LOGIN-01优先级: P0 (冒烟,必跑) / P1 (主流程) / P2 (异常分支) / P3 (边界/UI 细节)5.1 登录模块 (TC-LOGIN)对应文件:cases/test_login.pypages/login_page.py前置条件: 使用unlogin_page,不携带 cookie,导航至/login.html用例编号标题优先级输入操作预期结果TC-LOGIN-01用户名为空提交P1username“”, password“123456”点登录显示不能为空提示TC-LOGIN-02用户名长度 30P231 字符失焦显示用户名称1-30位字符;登录按钮不可点击TC-LOGIN-03用户名含特殊字符P2hello!#失焦显示不能有特殊字符;登录按钮不可点击TC-LOGIN-04密码错误P1py / 错误密码点登录显示账号或密码不正确TC-LOGIN-05账号不存在P1不存在的账号点登录显示账号或密码不正确TC-LOGIN-06登录成功-URL/TitleP0py / 123456点登录URL/index.html,Title“首页”TC-LOGIN-07登录成功-导航事件P0py / 123456点登录page.expect_navigation触发TC-LOGIN-08登录接口请求体校验P1py / 123456点登录POST /api/login,Content-Typejson,body 含正确字段TC-LOGIN-09登录接口响应校验P1py / 123456点登录status200,okTrueTC-LOGIN-10跳转注册页链接P2-点没有账号点这注册hrefregister.html,跳转后 Title“注册”补充建议用例 (待实现):TC-LOGIN-11: 密码字段空校验TC-LOGIN-12: 连续输错 N 次的锁定/验证码弹出 (若有)TC-LOGIN-13: 登录后刷新页面,登录态保持TC-LOGIN-14: 注销后再次访问受保护页,重定向到登录页5.2 注册模块 (TC-REG)对应文件:cases/test_register.pypages/register_page.py用例编号标题优先级校验点TC-REG-01用户名为空P1不能为空提示TC-REG-02用户名 30 字符P2“用户名称1-30位字符”;注册按钮 disabledTC-REG-03用户名含特殊字符P2“不能有特殊字符”;注册按钮 disabledTC-REG-04密码为空P1不能为空提示TC-REG-05密码长度 5/17 (边界外)P2“密码6-16位字符” (参数化)TC-REG-06密码含特殊字符P2“不能有特殊字符”TC-REG-07已存在账号P1注册错误提示可见TC-REG-08注册成功P0跳转/index.html,Title“首页”TC-REG-09跳登录页链接P2hreflogin.html,跳转后 Title“网站登录”补充建议用例:TC-REG-10: 密码长度边界 (6、16 字符) 应通过TC-REG-11: 用户名长度边界 (1、30 字符) 应通过TC-REG-12: 中文用户名 (3 字符) 应通过5.3 项目列表模块 (TC-PROJ-LIST)对应文件:cases/test_project_list.pypages/project_list_page.py前置:login_first已登录,导航至项目列表页用例编号标题优先级关键断言TC-PROJ-LIST-01新增弹窗-项目名为空提交P1模态框保持显示TC-PROJ-LIST-02新增弹窗-取消按钮P2模态框隐藏TC-PROJ-LIST-03新增重复项目 (Mock 400)P1弹出已存在TC-PROJ-LIST-04新增遇服务器异常 (Mock 500)P2弹出操作异常TC-PROJ-LIST-05新增成功 (Mock 200)P1模态框隐藏TC-PROJ-LIST-06搜索请求参数P1URL 含project_nametest,methodGETTC-PROJ-LIST-07搜索 0 条结果 (Mock)P2表格显示没有找到匹配的记录TC-PROJ-LIST-08搜索 1 条结果 (Mock)P1表格行数1TC-PROJ-LIST-09刷新按钮请求参数P2URL 含page1size15TC-PROJ-LIST-10行内 debugtalk 链接P2hrefdebugtalk.html?project_id1TC-PROJ-LIST-11行内删除-无权限 (Mock 403)P1二次确认 → 弹出无权限操作TC-PROJ-LIST-12行内编辑弹窗P1编辑模态框可见补充建议用例:TC-PROJ-LIST-13: 分页切换,验证分页参数TC-PROJ-LIST-14: 搜索为空时点搜索,展示全量TC-PROJ-LIST-15: 删除成功 (真实数据 二次确认)TC-PROJ-LIST-16: 列表排序 (若支持)5.4 添加项目模块 (TC-ADD-PROJ)对应文件:cases/test_add_project.pypages/add_project_page.py用例编号标题优先级输入预期TC-ADD-PROJ-01项目名特殊字符P2abc!保存按钮 disabledTC-ADD-PROJ-02项目名超长 (31 字符)P231 字符保存按钮 disabledTC-ADD-PROJ-03发布应用含特殊字符P2nameabc, appaa!保存按钮 disabledTC-ADD-PROJ-04必填全空P1全空保存按钮 disabledTC-ADD-PROJ-05保存成功 (真实)P0随机 uuid 名跳转list_project.htmlTC-ADD-PROJ-06项目名重复 (Mock 400)P1nameyo yo弹出已存在TC-ADD-PROJ-07服务器异常 (Mock 500)P2nametest弹出操作异常TC-ADD-PROJ-08保存成功并校验列表存在P0随机名列表 td 文本含该名称补充建议用例:TC-ADD-PROJ-09: 项目名长度边界 (1、30) 应通过TC-ADD-PROJ-10: 项目描述长度边界TC-ADD-PROJ-11: 取消保存,返回列表不创建5.5 添加模块模块 (TC-ADD-MOD)对应文件:cases/test_add_module.pypages/add_module_page.py前置: 拦截**/api/projectMock 返回选项数据用例编号标题优先级校验点TC-ADD-MOD-01模块名为空P1保存按钮 disabledTC-ADD-MOD-02所属项目未选P1保存按钮 disabledTC-ADD-MOD-03模块名重复 (Mock 400)P1弹出已存在TC-ADD-MOD-04保存成功 (Mock 200)P0跳转list_module.html补充建议用例:TC-ADD-MOD-05: 模块名特殊字符校验TC-ADD-MOD-06: 模块名长度边界TC-ADD-MOD-07: 项目下拉选项加载失败时的兜底5.6 环境列表模块 (TC-ENV)对应文件:cases/test_env_list.pypages/list_env_page.py用例编号标题优先级输入预期TC-ENV-01环境名为空P1“”提示不能为空TC-ENV-02环境名 40 字符P247 字符提示模块名称1-40位字符TC-ENV-03环境名特殊字符 (参数化)P2abc!/$32/\xx提示不能有特殊字符TC-ENV-04环境地址为空P1nameenv, addr“”提示不能为空TC-ENV-05环境地址协议非法 (参数化)P1abchttp/httpx:/httpsx://弹出操作异常,提示协议必须 http:/https:TC-ENV-06点取消关闭弹窗P3-模态框隐藏TC-ENV-07环境名已存在 (Mock 400)P1namepy1弹出py1 已存在TC-ENV-08新增成功 (Mock 200)P0namepy2, addr有效 url模态框隐藏补充建议用例:TC-ENV-09: 环境名长度边界 (1、40)TC-ENV-10: 环境地址合法 httpsTC-ENV-11: 环境列表编辑/删除TC-ENV-12: 同一项目多个环境的列表展示5.7 多账号协同场景 (TC-MULTI)对应文件:cases/more_accounts/test_x.py用例编号标题优先级流程TC-MULTI-01A 账号建项目, B 账号删除P1user1 创建 → user2 搜索 → user2 删除 → 校验 200补充建议用例:TC-MULTI-02: A 编辑过程中 B 删除同一项目,A 提交应报错TC-MULTI-03: A/B 同时新增同名项目,后者应被拒绝6. 测试覆盖矩阵6.1 功能 × 用例数量模块已有建议补充合计目标登录10414注册9312项目列表12416添加项目8311添加模块437环境列表8412多账号123合计5223756.2 用例类型 × 覆盖类型是否覆盖说明表单校验 (空/长度/特殊字符)✅各模块均已覆盖Happy Path 主流程✅登录/注册/新增成功接口请求参数校验✅expect_request接口响应校验✅expect_response异常状态码 (400/403/500)✅通过 Mock页面跳转/URL/Title✅expect_navigation/expect.to_have_url模态框交互✅取消、保存、二次确认列表搜索/刷新/分页⚠️分页未覆盖列表排序❌未覆盖文件上传/下载❌业务暂未涉及权限/角色⚠️仅 403 删除覆盖多 Tab/弹窗❌未覆盖7. 测试数据与环境管理7.1 测试账号用途用户名密码说明默认登录 (login_first)py123456普通账号多账号场景 (admin_context)admin(待补充)管理员账号注册成功用例uuid 前 8 位aa123456每次新建7.2 环境信息环境base_url说明当前框架默认http://47.116.12.183pytest.ini 配置本地调试通过--base-url命令行覆盖-7.3 数据清理策略注册成功、新增项目使用 uuid 保证唯一,不影响下次运行框架未自动清理产生的数据;建议每个迭代结束由后端脚本统一回收列表/详情类用例尽量使用 Mock 而非真实数据,降低环境耦合8. 执行计划8.1 触发方式触发场景命令范围本地全量python run.py全部用例本地按模块pytest cases/test_login.py单模块按优先级pytest -m p0(需补充 mark)冒烟用例按浏览器pytest --browser firefox兼容性CI 流水线pytest --alluredir ./reports全量 报告8.2 建议增加的 pytest markpytest.mark.p0# 冒烟pytest.mark.p1# 主流程pytest.mark.smoke# 上线前必跑pytest.mark.regression# 完整回归并在pytest.ini注册:markers p0: smoke level cases p1: main flow p2: exception branch p3: ui detail smoke: pre-release smoke regression: full regression8.3 执行频率触发点范围时长目标每次 PR 合入p0 修改模块≤ 3 分钟每日定时 (夜间)全量回归≤ 15 分钟版本发布前smoke regression≤ 30 分钟8.4 失败处理流程CI 失败 → 自动归档trace.zip 视频 截图至 Allure测试负责人在 Allure 报告查看失败用例用playwright show-trace test-results/trace.zip回放定位区分: 用例缺陷 (修用例) / 产品缺陷 (提 bug) / 环境问题 (重跑)同一用例连续失败 3 次自动标记为 flaky,移入隔离区9. 风险与对策风险影响对策测试环境数据被人工修改导致用例失败中主流程使用 Mock,关键资源使用唯一数据Mock 与真实接口契约漂移高定期 (月度) 对 Mock 数据进行真实接口校对登录态 cookie 跨用例污染中已通过unlogin_context隔离;新增用例时严格选择 fixture元素定位易变,UI 改动导致大量用例红高严格 POM,优先用get_by_label/语义化定位,避免脆弱 XPathtime.sleep滥用导致执行慢/不稳定中Code Review 阶段禁止 sleep,使用expect自动等待并发用例对共享数据竞争中多账号场景使用独立 context;避免在同一资源上并发 CUD报告产物体积过大低仅失败保留 trace/video;CI 配置产物保留 7 天10. 用例设计规范 (Style Guide)命名:test_功能_场景,如test_login_success_1、test_add_env_name_long类组织: 每个被测页面/模块对应一个测试类,类 docstring 作为 Allure feature用例 docstring: 一句话描述场景,框架会自动作为 Allure titlefixture: 用autouseTrue的start_for_each完成进入页面的前置断言: 优先expect(),禁止assert element.is_visible()(无自动等待)等待: 禁用time.sleep,使用expect/wait_for_load_state(networkidle)数据:唯一性数据 →uuid.uuid4()[:N]多组场景 →pytest.mark.parametrizePOM:元素定位全部封装为locator_*属性操作封装为fill_xxx/click_xxx/select_xxx用例代码不得出现裸 selectorMock: 仅用于异常分支与边界场景,放入mocks/mock_api.py报告: 必要时使用allure.step()注解关键步骤失败诊断: 每个用例都应可独立运行,失败信息能从 trace 视频复现11. 交付物与产出交付物路径测试案例代码cases/test_*.py页面对象代码pages/*.pyMock 数据mocks/mock_api.pyAllure 报告allure_report/index.html失败截图/视频/Tracetest-results/本设计计划书测试案例设计计划书.md12. 版本与变更记录版本日期作者变更说明v1.02026-05-20QA Team首次发布,覆盖 6 大模块 75 条目标用例附录 A: 常用命令速查# 安装依赖pipinstall-rrequirements.txt playwrightinstall# 运行全部python run.py# 按文件运行pytest cases/test_login.py-v# 按关键字pytest-klogin_success-v# 切浏览器pytest--browserfirefox# 录制playwright codegen http://47.116.12.183/login.html# 看 traceplaywright show-trace test-results/trace.zip# 生成并打开 Allureallure serve ./reports