【10. web 自动化测试及项目部署】:使用 skill 进行 web 自动化测试、数据库重置、项目阅读/部署文档
目录
1. 认识 playwright-cli
1.1 什么是 MCP
1.2 什么是 CLI
2. 搭建 playwright-cli 环境(Windows)
2.1 安装 node.js
2.2 安装 opencode
2.3 确认浏览器版本
2.4 安装 playwright-cli
2.5 playwright-cli 的使用
2.6 安装 playwright-cli skill
3. 生成 web 自动化测试报告
4. 构造测试数据(数据库重置)
5. 开始进行自动化测试
6. 关于 LLM "降智" 的问题
7. 小结
8. 编写项目 README 和 DEPOLY
9. 项目结语
1. 认识 playwright-cli
playwright 是微软出品的浏览器自动化测试框架。
就是一个 python 的包,通过 python 代码的方式就可以完成浏览器的自动化测试。
github 仓库:https://github.com/microsoft/playwright
为了让 playwright 能够很好的和 LLM 结合,微软在这个基础上,做出了两种封装:
- playwright-mcp
- playwright-cli
1.1 什么是 MCP
MCP(ModelContextProtocol)是一套"协议规范",目的是给LLM安装上"手"。
LLM 诞生之初,用户的使用方式单纯就是通过AI工具,向LLM提问,LLM返回答案,这个过程中,LLM 能听,能说,能思考,但是不能"做"。
为了让LLM也能"做事",人们就提出了MCP
- 用户向 AI 工具描述 "任务是啥"
- AI 工具把 "任务描述" 和 "当前有哪些MCP Server" 信息一起告诉给LLM
- LLM 结合任务和 MCP Server 的描述,决定给 MCP Server 发一个怎样的请求,来完成具体的任务。把这些结果统一返回给 AI 工具
- AI 工具通过 MCP Client 按照 LLM 的返回结果,发送请求给 MCP Server
- MCP Server 收到请求后,执行具体的任务(比如点击浏览器中的一个按钮),并返回响应给AI 工具。
- AI 工具把得到的结果再告诉 LLM,让 LLM 进行分析。
- LLM 分析完毕,把最终的结论返回给 AI 工具,最终再返回给用户。
1.2 什么是 CLI
CLI 全称为 Command Line Interface,也就是 "命令行界面"
ls,mkdir,rm 等指令,本质上就是 CLI 程序,opencode 也是 CLI 程序。
基于 MCP 的方式执行一个外部的任务,流程非常复杂。这就会导致整个过程消耗大量的 token,相比之下,同样是给 LLM 安装上"手",CLI 的方式就轻量很多了:
- 用户向 AI 工具描述"任务是啥"
- AI 工具把 "任务描述" 和 "当前有什么CLI工具" 信息一起告诉给 LLM
- LLM 结合任务和 CLI 工具信息,生成一个具体的 CLI 命令,返回给 AI 工具。
- AI 工具执行这个 CLI 命令,并把结果返回给 LLM 分析。
- LLM 把分析结果返回给 AI 工具,再最终返回给用户。
目前很多大厂的产品都在进行 "CLI化",经过实测,playwright-cli 相比于playwright-mcp,token 消耗只有 1/4。
在当前的时代,token 就是成本,token 就是效率。因此 playwright-cli 是当前更好的选择,因此后续就会使用 playwright-cli 的方式进行 web 自动化测试。
2. 搭建 playwright-cli 环境(Windows)
由于我们的浏览器是运行在 windows上,因此我们需要在 windows上搭建出 playwright-cli 环境。
2.1 安装 node.js
在 windows 上安装 node.js 很简单,打开 node.js 官网,点击下载windows安装程序,下载后双击安装包安装,一路next即可
安装完成后,确保 node 和 npm 命令可用:
PS C:\Users\75060> node Welcome to Node.js v24.18.0. Type ".help" for more information. >PS C:\Users\75060> npm npm <command> Usage: npm install install all the dependencies in your project npm install <foo> add the <foo> dependency to your project npm test run this project's tests npm run <foo> run the script named <foo> npm <command> -h quick help on <command> npm -l display usage info for all commands npm help <term> search for help on <term> (in a browser) npm help npm more involved overview (in a browser) All commands: access, adduser, approve-scripts, audit, bugs, cache, ci, completion, config, dedupe, deny-scripts, deprecate, diff, dist-tag, docs, doctor, edit, exec, explain, explore, find-dupes, fund, get, help, help-search, init, install, install-ci-test, install-test, link, ll, login, logout, ls, org, outdated, owner, pack, ping, pkg, prefix, profile, prune, publish, query, rebuild, repo, restart, root, run, sbom, search, set, shrinkwrap, stage, star, stars, start, stop, team, test, token, trust, undeprecate, uninstall, unpublish, unstar, update, version, view, whoami Specify configs in the ini-formatted file: C:\Users\75060\.npmrc or on the command line via: npm <command> --key=value More configuration info: npm help config Configuration fields: npm help 7 config npm@11.16.0 D:\Software\Nodejs\node_modules\npm2.2 安装 opencode
和 Linux 版本相同,使用 npm 安装
npm i -g opencode-ai2.3 确认浏览器版本
虽然 playwright-cli 支持多种主流浏览器,但还是建议使用 chrome 最新版。
"主流浏览器" 指的是chrome,edge,firefox,safari 等。不包括国产浏览器。
国产浏览器大多是基于旧版本(可能是若干年前的版本)chrome 内核,重新包装了一套界面。
2.4 安装 playwright-cli
playwright-cli 使用 npm 安装:
npm install -g @playwright/cli@latest当前,AI LLM 生态中的,TypeScript / node 在工程化方面占据了很重要的席位,因此我们看到的很多 AI LLM 相关工具都是基于 TypeScript /node 生态来构建的。
2.5 playwright-cli 的使用
简单的测试,如果安装成功,尝试用其打开百度主页:
palywright-cli open baidu.com --headed--head参数非常关键。
- 如果不加这个参数,默认会以 "无头"(headless)的方式运行 chrome,此时浏览器窗口不可见(通过隐藏窗口,降低内存占用,也防止用户操作产生干扰)。
- 无头模式在生产级环境中更多使用,但是我们在初学阶段,还是使用 "有头" 的方式,更直观地观察到浏览器自动化执行的过程。
通过下列命令可以查看到更完整的参数选项:
playwright-cli help这么多选项不需要我们看,也不需要我们掌握,我们只要让 AI 读取这些内容,理解 playwright-cli 的用法即可,这些固定的,繁琐的工作,能丢给 AI 的,都尽量丢给 AI
2.6 安装 playwright-cli skill
为了让 AI 可以更好的理解 playwright-cli 的用法,可以安装官方提供的 skill:
playwright-cli install --skill agentsplaywright-cli 相当于一个工具箱,里面有很多工具(螺丝刀,扳手,电钻,膨胀螺丝...)
skill 则相当于是这套工具的"说明书"。(这个说明书是专门给 AI 看的)
上面这个命令执行时所在的目录,需要注意:
- 如果是在用户目录中执行(形如C:\Users\75060),此时安装的 skill 全局有效。
- 如果是在当前项目录中执行,此时安装的 skill 只在当前项目中生效。
这个命令的本质会在当前目录中下载对应的 skill 目录,放到 .agent 目录中。
- 如果 .agent 是在用户目录下,则全局生效(主流 AI 工具在各个目录中,均可读取到这个skill)
- 如果 .agent 是在项目录下,则只在当前项目中生效。
此处我选择安装在用户目录中,效果如下:
其中的 SKILL.md 就是这个 skill 的入口文档.
启动 opencode(windows 端启动),使用 /skill 命令查看当前的 skill,可以看到 plawright-cli skill已经安装成功。
3. 生成 web 自动化测试报告
回到 Linux 中的 opencode,让其生成一套 web 自动化的测试流程
根据 @SPEC.md 设计一套 web ui 测试用例,baseurl 为 http://虚拟机ip:端口号(如8080)/
结果生成到 web_testcase.md 中.
# OJ 系统 Web 自动化测试文档 ## 1. 测试概述 ### 1.1 测试目标 对 OJ 在线判题系统的前端功能进行全面的 Web 自动化测试,确保系统各项功能正常运行。 ### 1.2 测试环境 - **服务器地址**: `http://192.168.26.132:8080` - **浏览器**: Chrome / Firefox / Edge - **测试框架**: Playwright - **管理员账户**: 用户名 `admin` / 密码 `vr.666666` ### 1.3 测试范围 | 模块 | 测试内容 | |------|----------| | 认证模块 | 登录、注册、用户名唯一性校验、退出登录 | | 题目模块 | 题目列表、题目筛选、题目详情 | | 判题模块 | 代码提交、判题结果展示 | | 管理后台 | 题目增删改查、测试用例配置 | | 落地页 | 大屏展示、数据统计展示、导航链接 | --- ## 2. 测试用例详细设计 ### 2.1 认证模块 #### TC-001: 用户登录成功 | 项目 | 内容 | |------|------| | **用例ID** | TC-001 | | **用例名称** | 用户登录成功 | | **前置条件** | 用户已注册(普通用户或管理员) | | **测试步骤** | 1. 打开登录页面 `http://192.168.26.132:8080/login.html`<br>2. 输入有效的用户名和密码<br>3. 点击登录按钮 | | **预期结果** | 1. 登录按钮显示 loading 状态<br>2. 登录成功后页面跳转到首页<br>3. 导航栏显示当前用户名<br>4. 页面无报错信息 | | **测试数据** | 普通用户: `testuser` / `test123456`<br>管理员: `admin` / `vr.666666` | #### TC-002: 用户登录失败 - 用户名错误 | 项目 | 内容 | |------|------| | **用例ID** | TC-002 | | **用例名称** | 用户登录失败-用户名错误 | | **测试步骤** | 1. 打开登录页面<br>2. 输入不存在的用户名<br>3. 输入任意密码<br>4. 点击登录按钮 | | **预期结果** | 1. 显示错误提示"用户名或密码错误"<br>2. 输入框保持不变,可重新输入<br>3. 页面不跳转 | #### TC-003: 用户登录失败 - 密码错误 | 项目 | 内容 | |------|------| | **用例ID** | TC-003 | | **用例名称** | 用户登录失败-密码错误 | | **测试步骤** | 1. 打开登录页面<br>2. 输入已注册的用户名<br>3. 输入错误的密码<br>4. 点击登录按钮 | | **预期结果** | 1. 显示错误提示"用户名或密码错误"<br>2. 输入框保持不变 | #### TC-004: 用户登录 - 表单验证 | 项目 | 内容 | |------|------| | **用例ID** | TC-004 | | **用例名称** | 用户登录-表单验证 | | **测试步骤** | 1. 打开登录页面<br>2. 不输入任何内容,直接点击登录<br>3. 验证空用户名提示<br>4. 输入用户名,不输入密码,点击登录<br>5. 验证空密码提示 | | **预期结果** | 1. 空用户名: 显示"用户名不能为空"<br>2. 空密码: 显示"密码不能为空" | #### TC-005: 用户注册成功 | 项目 | 内容 | |------|------| | **用例ID** | TC-005 | | **用例名称** | 用户注册成功 | | **前置条件** | 测试用户名不存在 | | **测试步骤** | 1. 打开注册页面 `http://192.168.26.132:8080/register.html`<br>2. 生成唯一用户名 `newuser_${Date.now()}`<br>3. 输入密码 `test123456`<br>4. 再次输入相同密码确认<br>5. 点击注册按钮 | | **预期结果** | 1. 显示注册成功提示<br>2. 1.5秒后自动跳转到登录页面 | | **测试数据** | 用户名: `newuser_${Date.now()}`(动态生成)/ 密码: `test123456` | | **可重复执行** | 是,每次使用唯一用户名 | #### TC-006: 用户注册 - 用户名已存在 | 项目 | 内容 | |------|------| | **用例ID** | TC-006 | | **用例名称** | 用户注册-用户名已存在 | | **前置条件** | 用户 `admin` 必须存在 | | **测试步骤** | 1. 打开注册页面<br>2. 输入已存在的用户名 `admin`<br>3. 等待用户名唯一性检查(自动检测)<br>4. 输入密码和确认密码<br>5. 点击注册按钮 | | **预期结果** | 1. 显示用户名已被占用的错误提示<br>2. 注册按钮不可点击或提交被拒绝 | | **可重复执行** | 是,`admin` 为预置管理员账户不会被删除 | #### TC-007: 用户注册 - 密码不一致 | 项目 | 内容 | |------|------| | **用例ID** | TC-007 | | **用例名称** | 用户注册-密码不一致 | | **测试步骤** | 1. 打开注册页面<br>2. 输入有效用户名<br>3. 输入密码 `test123456`<br>4. 输入不同的确认密码 `test1234567`<br>5. 点击注册按钮 | | **预期结果** | 1. 显示"两次输入的密码不一致"错误提示 | #### TC-008: 用户注册 - 用户名格式验证 | 项目 | 内容 | |------|------| | **用例ID** | TC-008 | | **用例名称** | 用户注册-用户名格式验证 | | **测试步骤** | 分别测试以下用户名格式:<br>1. 空用户名<br>2. 用户名少于3字符: `ab`<br>3. 用户名超过20字符<br>4. 用户名包含特殊字符: `user@name`<br>5. 有效用户名: `valid_user123` | | **预期结果** | 1. 空: "用户名不能为空"<br>2. 少于3字符: "用户名至少需要3个字符"<br>3. 超过20字符: "用户名最多20个字符"<br>4. 特殊字符: "用户名只能包含字母、数字和下划线"<br>5. 有效格式: 通过验证 | #### TC-009: 用户注册 - 密码长度验证 | 项目 | 内容 | |------|------| | **用例ID** | TC-009 | | **用例名称** | 用户注册-密码长度验证 | | **测试步骤** | 分别测试以下密码:<br>1. 空密码<br>2. 密码少于6字符: `12345`<br>3. 密码超过50字符<br>4. 有效密码: `test123456` | | **预期结果** | 1. 空: "密码不能为空"<br>2. 少于6字符: "密码至少需要6个字符"<br>3. 超过50字符: "密码最多50个字符"<br>4. 有效长度: 通过验证 | #### TC-010: 用户退出登录 | 项目 | 内容 | |------|------| | **用例ID** | TC-010 | | **用例名称** | 用户退出登录 | | **前置条件** | 用户已登录 | | **测试步骤** | 1. 用户已登录状态<br>2. 点击导航栏的"退出登录"按钮 | | **预期结果** | 1. 清除用户 session<br>2. 页面跳转到登录页面<br>3. 尝试直接访问题目列表会被重定向到登录页 | #### TC-011: 未登录用户访问受保护页面 | 项目 | 内容 | |------|------| | **用例ID** | TC-011 | | **用例名称** | 未登录用户访问受保护页面 | | **测试步骤** | 1. 清除所有登录状态(清除 cookies/localStorage)<br>2. 直接访问 `http://192.168.26.132:8080/problem_list.html`<br>3. 直接访问 `http://192.168.26.132:8080/admin/admin.html` | | **预期结果** | 1. 页面自动重定向到登录页面 | --- ### 2.2 题目模块 #### TC-012: 题目列表展示 | 项目 | 内容 | |------|------| | **用例ID** | TC-012 | | **用例名称** | 题目列表展示 | | **前置条件** | 用户已登录 | | **测试步骤** | 1. 登录系统<br>2. 进入题目列表页面 | | **预期结果** | 1. 页面正确显示题目列表<br>2. 每道题目显示: 题号、标题、难度、时间限制、内存限制<br>3. 难度使用不同颜色标识(简单-绿色/中等-黄色/困难-红色) | #### TC-013: 题目列表筛选 - 按难度 | 项目 | 内容 | |------|------| | **用例ID** | TC-013 | | **用例名称** | 题目列表筛选-按难度 | | **前置条件** | 系统中存在不同难度的题目 | | **测试步骤** | 1. 在题目列表页面<br>2. 点击"全部"筛选按钮<br>3. 点击"简单"筛选按钮<br>4. 点击"中等"筛选按钮<br>5. 点击"困难"筛选按钮 | | **预期结果** | 1. 点击后按钮高亮显示<br>2. 列表只显示对应难度的题目<br>3. 切换筛选条件后列表正确更新 | #### TC-014: 题目列表为空状态 | 项目 | 内容 | |------|------| | **用例ID** | TC-014 | | **用例名称** | 题目列表为空状态 | | **前置条件** | 数据库中没有题目 | | **测试步骤** | 进入题目列表页面 | | **预期结果** | 显示"暂无题目"提示和空状态图标 | #### TC-015: 题目详情展示 | 项目 | 内容 | |------|------| | **用例ID** | TC-015 | | **用例名称** | 题目详情展示 | | **前置条件** | 系统中存在题目 | | **测试步骤** | 1. 在题目列表点击某道题目<br>2. 进入题目详情页面 | | **预期结果** | 1. 页面正确显示题目标题<br>2. 显示难度标签<br>3. 显示时间限制和内存限制<br>4. 显示完整的题目描述<br>5. 显示示例输入/输出(如有) | #### TC-016: 代码编辑器功能 | 项目 | 内容 | |------|------| | **用例ID** | TC-016 | | **用例名称** | 代码编辑器功能 | | **前置条件** | 进入题目详情页面 | | **测试步骤** | 1. 确认代码编辑器加载成功<br>2. 在编辑器中输入代码 `cout << "Hello";`<br>3. 切换语言为 Python<br>4. 确认编辑器内容变化 | | **预期结果** | 1. Ace 编辑器正常加载<br>2. 代码可正常输入<br>3. 切换语言后,代码模板更新 | --- ### 2.3 判题模块 #### TC-017: 代码提交成功 - 答案正确 | 项目 | 内容 | |------|------| | **用例ID** | TC-017 | | **用例名称** | 代码提交成功-答案正确 | | **前置条件** | 存在一道简单题目及其测试用例 | | **测试步骤** | 1. 进入某道题目的详情页<br>2. 输入正确答案的代码<br>3. 点击"提交代码"按钮<br>4. 等待判题结果 | | **预期结果** | 1. 按钮显示"提交中..."状态<br>2. 显示"判题中..."状态<br>3. 判题完成后显示绿色"通过"状态<br>4. 显示执行时间 | | **测试数据** | 示例:两数相加题目 | #### TC-018: 代码提交 - 答案错误 | 项目 | 内容 | |------|------| | **用例ID** | TC-018 | | **用例名称** | 代码提交-答案错误 | | **测试步骤** | 1. 进入题目详情页<br>2. 输入错误答案的代码<br>3. 提交代码 | | **预期结果** | 1. 显示红色"答案错误"状态<br>2. 不显示执行时间或显示实际时间 | #### TC-019: 代码提交 - 编译错误 | 项目 | 内容 | |------|------| | **用例ID** | TC-019 | | **用例名称** | 代码提交-编译错误 | | **测试步骤** | 1. 进入题目详情页<br>2. 输入有语法错误的代码(如 `#include <iostream>` 写成 `#include <iostream>` 但语法错误)<br>3. 提交代码 | | **预期结果** | 1. 显示紫色"编译错误"状态<br>2. 显示具体的编译错误信息 | #### TC-020: 代码提交 - 运行错误 | 项目 | 内容 | |------|------| | **用例ID** | TC-020 | | **用例名称** | 代码提交-运行错误 | | **测试步骤** | 1. 进入题目详情页<br>2. 输入会触发运行时错误的代码(如除零错误、数组越界)<br>3. 提交代码 | | **预期结果** | 1. 显示粉色"运行错误"状态<br>2. 显示运行时错误信息 | #### TC-021: 代码提交 - 超时 | 项目 | 内容 | |------|------| | **用例ID** | TC-021 | | **用例名称** | 代码提交-超时 | | **测试步骤** | 1. 进入题目详情页<br>2. 输入包含无限循环的代码<br>3. 提交代码 | | **预期结果** | 1. 显示橙色"超时"状态<br>2. 不显示执行时间或显示超时提示 | #### TC-022: 判题结果轮询 | 项目 | 内容 | |------|------| | **用例ID** | TC-022 | | **用例名称** | 判题结果轮询 | | **测试步骤** | 1. 提交代码后<br>2. 观察页面状态变化<br>3. 等待最终结果 | | **预期结果** | 1. 每秒自动刷新判题状态<br>2. 状态从"判题中"变为最终结果<br>3. 轮询在获得最终结果后自动停止 | #### TC-023: 空代码提交 | 项目 | 内容 | |------|------| | **用例ID** | TC-023 | | **用例名称** | 空代码提交 | | **测试步骤** | 1. 进入题目详情页<br>2. 不输入任何代码<br>3. 点击提交按钮 | | **预期结果** | 1. 弹出提示"请输入代码"或类似提示<br>2. 不发送提交请求 | --- ### 2.4 管理后台模块 #### TC-024: 管理员访问管理后台 | 项目 | 内容 | |------|------| | **用例ID** | TC-024 | | **用例名称** | 管理员访问管理后台 | | **前置条件** | 使用管理员账户登录 | | **测试步骤** | 1. 使用管理员账号 `admin` / `vr.666666` 登录<br>2. 自动跳转或手动进入管理后台 | | **预期结果** | 1. 成功进入管理后台<br>2. 显示"题目管理"标题<br>3. 显示"新增题目"按钮 | #### TC-025: 普通用户禁止访问管理后台 | 项目 | 内容 | |------|------| | **用例ID** | TC-025 | | **用例名称** | 普通用户禁止访问管理后台 | | **前置条件** | 使用普通用户账户登录 | | **测试步骤** | 1. 使用普通用户账号登录<br>2. 尝试访问 `http://192.168.26.132:8080/admin/admin.html` | | **预期结果** | 1. 显示无权限提示<br>2. 自动跳转到题目列表页面 | #### TC-026: 创建新题目 | 项目 | 内容 | |------|------| | **用例ID** | TC-026 | | **用例名称** | 创建新题目 | | **前置条件** | 管理员已登录 | | **测试步骤** | 1. 进入管理后台<br>2. 点击"新增题目"按钮<br>3. 生成唯一标题: `测试题目_${Date.now()}`<br>4. 填写题目描述: "给定两个整数,返回它们的和"<br>5. 选择难度: 简单<br>6. 时间限制: 1000ms<br>7. 内存限制: 256MB<br>8. 添加测试用例: 输入 "1 2" 输出 "3"<br>9. 点击"创建"按钮 | | **预期结果** | 1. 弹出新增题目模态框<br>2. 题目创建成功后显示"创建成功"提示<br>3. 模态框关闭<br>4. 题目列表更新显示新题目 | | **测试数据** | 标题: `测试题目_${Date.now()}`(动态生成)<br>描述: `给定两个整数,返回它们的和`<br>难度: `easy`<br>时间限制: `1000`<br>内存限制: `256`<br>测试用例: 输入 `1 2` 输出 `3` | | **可重复执行** | 是,每次使用唯一标题 | #### TC-027: 编辑题目 | 项目 | 内容 | |------|------| | **用例ID** | TC-027 | | **用例名称** | 编辑题目 | | **前置条件** | 系统中存在至少一道题目 | | **测试步骤** | 1. 进入管理后台<br>2. **先创建一个测试题目**(标题: `测试题目编辑_${Date.now()}`)<br>3. 点击该题目的"编辑"按钮<br>4. 修改题目标题<br>5. 修改题目描述<br>6. 点击"保存"按钮 | | **预期结果** | 1. 弹出编辑题目模态框<br>2. 表单预填充当前题目信息<br>3. 保存成功后显示"更新成功"提示<br>4. 题目列表中显示更新后的信息 | | **可重复执行** | 是,使用动态生成的唯一标题 | #### TC-028: 删除题目 | 项目 | 内容 | |------|------| | **用例ID** | TC-028 | | **用例名称** | 删除题目 | | **前置条件** | 管理员已登录 | | **测试步骤** | 1. 进入管理后台<br>2. **先创建一个测试题目**(标题: `测试题目删除_${Date.now()}`)<br>3. 点击该题目的"删除"按钮<br>4. 在确认弹窗中点击"确定" | | **预期结果** | 1. 弹出确认对话框"确定要删除这道题目吗?"<br>2. 确认后显示"删除成功"提示<br>3. 题目从列表中移除 | | **可重复执行** | 是,使用动态生成的唯一标题,删除自己创建的数据 | #### TC-029: 取消删除题目 | 项目 | 内容 | |------|------| | **用例ID** | TC-029 | | **用例名称** | 取消删除题目 | | **前置条件** | 管理员已登录 | | **测试步骤** | 1. 进入管理后台<br>2. **先创建一个测试题目**(标题: `测试题目取消删除_${Date.now()}`)<br>3. 点击该题目的"删除"按钮<br>4. 在确认弹窗中点击"取消" | | **预期结果** | 1. 确认对话框关闭<br>2. 题目未被删除<br>3. 题目列表保持不变 | | **可重复执行** | 是,使用动态生成的唯一标题,删除自己创建的数据 | #### TC-030: 添加多个测试用例 | 项目 | 内容 | |------|------| | **用例ID** | TC-030 | | **用例名称** | 添加多个测试用例 | | **前置条件** | 进入新增/编辑题目模态框 | | **测试步骤** | 1. 打开新增或编辑题目模态框<br>2. 点击"添加"按钮添加测试用例<br>3. 添加 3 个测试用例 | | **预期结果** | 1. 成功添加多个测试用例字段<br>2. 可以分别填写每个用例的输入和预期输出<br>3. 可以单独删除某个测试用例 | #### TC-031: 创建题目 - 表单验证 | 项目 | 内容 | |------|------| | **用例ID** | TC-031 | | **用例名称** | 创建题目-表单验证 | | **测试步骤** | 1. 进入管理后台<br>2. 点击"新增题目"按钮<br>3. 不填写任何内容,直接点击"创建" | | **预期结果** | 1. 显示"请填写完整信息"错误提示<br>2. 不会发送创建请求 | #### TC-032: 题目列表显示验证 | 项目 | 内容 | |------|------| | **用例ID** | TC-032 | | **用例名称** | 题目列表显示验证 | | **前置条件** | 系统中存在多道不同难度的题目 | | **测试步骤** | 在管理后台查看题目列表 | | **预期结果** | 1. 表格显示: ID、标题、难度、时间限制、操作<br>2. 操作列有"编辑"和"删除"两个按钮<br>3. 难度使用正确的颜色标识 | --- ### 2.5 页面 UI 测试 #### TC-033: 登录页面样式验证 | 项目 | 内容 | |------|------| | **用例ID** | TC-033 | | **用例名称** | 登录页面样式验证 | | **测试步骤** | 打开登录页面并检查 | | **预期结果** | 1. 深色主题背景 (#0F172A)<br>2. 居中的登录卡片<br>3. 绿色主题按钮 (#22C55E)<br>4. 输入框有正确的 focus 效果<br>5. 页面有赛博朋克风格的网格背景 | #### TC-034: 响应式布局测试 | 项目 | 内容 | |------|------| | **用例ID** | TC-034 | | **用例名称** | 响应式布局测试 | | **测试步骤** | 1. 在桌面浏览器(1920px)查看页面<br>2. 调整浏览器窗口到平板尺寸(768px)<br>3. 调整到手机尺寸(375px) | | **预期结果** | 1. 桌面: 题目列表显示完整的表格列<br>2. 平板/手机: 表格列自适应,题目卡片式展示<br>3. 导航栏自适应显示 | #### TC-035: 页面加载状态 | 项目 | 内容 | |------|------| | **用例ID** | TC-035 | | **用例名称** | 页面加载状态 | | **测试步骤** | 1. 刷新题目列表页面<br>2. 刷新题目详情页面 | | **预期结果** | 1. 显示 loading 状态(spinner)<br>2. 数据加载完成后显示实际内容 | --- ### 2.6 落地页模块 #### TC-036: 落地页展示 | 项目 | 内容 | |------|------| | **用例ID** | TC-036 | | **用例名称** | 落地页展示 | | **测试步骤** | 1. 打开落地页 `http://192.168.26.132:8080/index.html`<br>2. 检查页面核心元素 | | **预期结果** | 1. 页面正常加载,无报错<br>2. 显示 OJ 系统标题/Logo<br>3. 显示统计数据(题目数量、用户数量、提交次数等)<br>4. 深色主题背景 | #### TC-037: 落地页导航链接 - 登录 | 项目 | 内容 | |------|------| | **用例ID** | TC-037 | | **用例名称** | 落地页导航链接-登录 | | **测试步骤** | 1. 在落地页点击"登录"按钮 | | **预期结果** | 1. 页面跳转到登录页面 `http://192.168.26.132:8080/login.html` | #### TC-038: 落地页导航链接 - 注册 | 项目 | 内容 | |------|------| | **用例ID** | TC-038 | | **用例名称** | 落地页导航链接-注册 | | **测试步骤** | 1. 在落地页点击"注册"按钮 | | **预期结果** | 1. 页面跳转到注册页面 `http://192.168.26.132:8080/register.html` | #### TC-039: 落地页导航链接 - 题目列表 | 项目 | 内容 | |------|------| | **用例ID** | TC-039 | | **用例名称** | 落地页导航链接-题目列表 | | **测试步骤** | 1. 在落地页点击"开始刷题"或题目列表入口 | | **预期结果** | 1. 未登录时:跳转登录页面<br>2. 已登录时:跳转题目列表页面 | #### TC-040: 落地页大屏展示效果 | 项目 | 内容 | |------|------| | **用例ID** | TC-040 | | **用例名称** | 落地页大屏展示效果 | | **测试步骤** | 1. 在桌面浏览器(1920px)打开落地页<br>2. 检查页面布局和视觉效果 | | **预期结果** | 1. 统计数据以大字号展示<br>2. 页面布局大气、居中<br>3. 背景样式符合赛博朋克/深色主题风格 | --- ## 3. 测试执行流程 ### 3.1 环境准备 ```bash # 安装 Playwright npm install -D @playwright/test npx playwright install chromium ``` ### 3.2 测试脚本结构 ``` tests/ └── e2e/ ├── config.js # 测试配置 ├── login.spec.js # 登录相关测试 ├── register.spec.js # 注册相关测试 ├── problems.spec.js # 题目相关测试 ├── submit.spec.js # 判题相关测试 ├── admin.spec.js # 管理后台测试 └── landing.spec.js # 落地页测试 ``` ### 3.3 测试配置示例 ```javascript // playwright.config.js module.exports = { testDir: './tests/e2e', timeout: 30000, retries: 1, use: { baseURL: 'http://192.168.26.132:8080', headless: true, screenshot: 'only-on-failure', video: 'retain-on-failure', }, projects: [ { name: 'chromium', use: { browserName: 'chromium' } }, { name: 'firefox', use: { browserName: 'firefox' } }, ], }; ``` ### 3.4 测试执行命令 ```bash # 运行所有测试 npx playwright test # 运行特定测试文件 npx playwright test tests/e2e/login.spec.js # 运行特定标签的测试 npx playwright test --grep "登录" # 生成测试报告 npx playwright test --reporter=html ``` --- ## 4. 测试数据准备 ### 4.1 预置测试用户 | 用户名 | 密码 | 角色 | 用途 | |--------|------|------|------| | admin | vr.666666 | 管理员 | 管理后台测试 | | testuser | test123456 | 普通用户 | 普通用户功能测试 | ### 4.2 预置测试题目 | 题号 | 标题 | 难度 | 描述 | |------|------|------|------| | 1 | 两数之和 | easy | 给定两个整数,返回它们的和 | | 2 | 反转字符串 | medium | 给定一个字符串,返回它的反转 | | 3 | 质数判定 | hard | 判断一个数是否为质数 | --- ## 5. 缺陷跟踪 ### 5.1 缺陷严重等级 | 等级 | 说明 | |------|------| | P0 | 系统崩溃,无法继续测试 | | P1 | 核心功能无法使用 | | P2 | 功能有缺陷,但有替代方案 | | P3 | UI/UX 问题,不影响功能 | ### 5.2 缺陷记录表 | 缺陷ID | 用例ID | 描述 | 严重等级 | 状态 | |--------|--------|------|----------|------| | - | - | - | - | - | --- ## 6. 附录 ### 6.1 API 端点参考 | 方法 | 端点 | 描述 | |------|------|------| | POST | /api/auth/register | 注册 | | POST | /api/auth/login | 登录 | | GET | /api/problems | 题目列表 | | GET | /api/problems/:id | 题目详情 | | POST | /api/admin/problems | 创建题目 | | PUT | /api/admin/problems/:id | 更新题目 | | DELETE | /api/admin/problems/:id | 删除题目 | | POST | /api/submit | 提交代码 | | GET | /api/submissions/:id | 提交详情 | ### 6.2 判题状态说明 | 状态 | 显示 | 说明 | |------|------|------| | pending | 判题中 | 等待判题 | | accepted | 通过 | 答案正确 | | wrong_answer | 答案错误 | 输出结果不符 | | time_limit_exceeded | 超时 | 超出时间限制 | | runtime_error | 运行错误 | 程序运行时崩溃 | | compile_error | 编译错误 | 代码编译失败 | --- *文档版本: v1.0* *创建日期: 2026-07-22*4. 构造测试数据(数据库重置)
虽然测试用例文档已经有了,但是还不能直接开始测试,测试能通过,功能能正确,取决于两方面:
- 代码逻辑正确
- 数据库中的数据正确
要想验证代码逻辑,需要先保证数据库中,有正确的代码。
由于前面已经进行了多轮单元测试和接口自动化测试,数据库中已经有很多"测试数据"。这些数据可能就对接下来的测试造成负面干扰,因此需要先确保数据库是"干净"的,把冗余数据删除掉,只保留需要的数据,这个过程不需要手动完成,可以让 AI 写一个工具,完成"数据库重置工作"。
@SEPC.md @web自动化测试文档.md 根据 web 自动化测试文档,编写一个程序(C++),实现对数据库进行重置的效果,删除数据库中的冗余的内容,构造接口自动化需要的必要数据.
注意:数据库充值程序是一个很危险的程序,一定要确认好,你操作的数据库确实是可以删除的。千万不要在生产环境上运行这个程序.
5. 开始进行自动化测试
将项目使用 git 提交至仓库,然后在 windows 端进行克隆:
git clone 仓库链接在克隆下来的项目中打开 opencode
使用 skill 并结合 web自动化测试文档
测试用例比较多,直接一口气执行,时间长且可能不稳定,所以可以分批次的执行
/playwright-cli @web自动化测试文档.md 根据文档描述,使用有头模式(--headed),完成 web 自动化测试,每个操作之间停顿 1 秒,方便我进行观察,先进行 xx~xx 测试用例的执行.
opencode 执行的过程中是有 bug 的,opencode 进行 web 自动化测试的时候,打开网页然后就卡住了,我们需要手动暂停任务(esc 按两次),然后说:
继续执行
对于上述测试用例来说,初次执行通常不会很顺利,需要有一个"探索"的过程。
当用例最终通过之后,可以让 AI 把执行步骤总结成文档,这样后续再执行,直接按照总结好的文档来进行操作即可。
将上述执行过程,总结到 @web自动化测试文档-playwright-cli.md
针对出现问题,AI 反复尝试无法解决的情况,我们应该引导 AI,如:
@public/problem.html 当前针对提交的代码出错的情况(编译错误,运行出错,运行超时),此时后端通过接口测试,已经验证了服务器返回了出错的详细情况 @tests/python/test_api.py(接口测试代码参见这个文件),对应的后端代码参见 @src/handler/submit_handler.cc。但是前端页面上没有展示出具体出错的详细信息,确认这个问题,并修改。
6. 关于 LLM "降智" 的问题
在项目的后期,能明显感觉到 LLM 似乎开始 "降智" 了。
这种情况在 LLM 中是比较普遍的情况。一个 LLM 的 "智商" 是和供应商提供的 "算力" 是直接相关的。
一个新模型上线之初,用户量少,此时单位请求能够使用的算力就更多,模型能力就更强;随着用户量逐渐增加,如果服务商没有对算力进行扩容,那么单个请求使用的算力可能会大幅度减少,从而出现 "降智"。
大家在学习阶段,一定是选择合适的模型。
7. 小结
通过上面的一系列操作,我们就完成了web自动化测试的整个过程。
- 技术上基于 playwright-cli 实现浏览器操作
- 测试之前,需要先根据项目代码,梳理出一个初步的测试文档。
- 每一次都执行文档中的一部分用例,来 "趟一遍坑"。
- 完成初次测试之后,可以把具体操作步骤总结下来,填写到另一个文档中。
- 针对不通过的用例,可以单独执行这个用例,进一步分析和解决问题。
- 所有用例都 "趟完一遍" 之后,可以根据总结出的文档,再次进行测试,进一步验证。
8. 编写项目 README 和 DEPOLY
一个开源项目通常都需要有介绍文档和一个部署文档。我们可以让 AI 帮我们生成文档,使项目看起来 "更专业"。
@SEPC.md 根据文档描述和代码仓库内容,编写 DEPOLY.md(项目部署文档)和 README.md(项目介绍文档)
AI 完成文档编写后,可以尝试找一台新机器(云服务器)进行从头部署,看看是否可行,其中可能会遇到很多问题,比如依赖/库无法下载(可能 AI 是从 github 上下载,不想 FQ 可以让 AI 进行修改)
9. 项目结语
到这一步,本项目完结撒花。
通过上面的学习过程,我们不光学习项目本身,更重要的是学习理解 Vibe Coding 这种新时代的开发方式。
目前来看,无论是大公司还是中小公司,都把 Vibe Coding 作为非常重要的推进点,因为 AI 确实能帮助我们大幅度提高代码开发效率。
另一方面,大家掌握了 Vibe Coding 这一项技能之后,还可以基于 Vibe Coding 重构自己做过的其他项目,或者基于 Vibe Coding 开发任何你想做的新项目。天高海阔,任由各位自由发挥。
