# Jog System · Cursor 自动化测试输入规范(全量需求展开) **文档版本** · **V1.0(Cursor)** · **生成日期** · **2026-05-18** | 属性 | 内容 | | :--- | :--- | | **定位** | **AI(含 Cursor Agent)生成自动化测试代码时的唯一输入**;不依赖其他 doc 文件即可推导 JUnit / MockMvc / Testcontainers / Vitest / Playwright / k6 等用例 | | **需求溯源** | 全文展开自 `doc/jog-system-requirements.md`(V1.0,2026-05-17)中的 **FR**、**AC**、**§3 非功能**、**§4 权限矩阵**、**§5 界面**、**§6 测试验收** | | **实现校准** | HTTP 路径与 Controller 以 **附录 A** 为准(当前 `jog-*` 仓库);与需求文字中的示例路径不一致时,**以代码为准**,并在用例 `notes` 中标注「需求差异」 | | **并存说明** | 若与 `jog-system-automated-test-plan.md` 同时存在,**以本 `cursor` 文档为 AI 唯一输入** | --- ## 0. 使用方式(写给 AI / Cursor) 1. **仅依据本文档**生成测试:从「第 6 章」起按 `TC-*` 编号实现;接口路径查附录 A。 2. 每条用例必须使用 **第 5 章 JSON 模板** 输出设计(可先批量生成 YAML/JSON fixture,再写代码)。 3. `trace` 字段必须含 **FR-* / AC-* / NF-* / PM-* / UI-* / API-*` 之一,便于覆盖率报告。 4. 标注 `implementation_gap` 的用例:实现未达需求时,实现 **`@Disabled` + 原因** 或 **`xfail`**,不得静默改预期。 5. **优先级**:`P0` 阻塞发布;`P1` 阻塞合并;`P2` 迭代补齐。 --- ## 1. 仓库与已有验证事实(非需求,仅供上下文) | 代号 | 说明 | | :--- | :--- | | T-01 | `mvn -B test` 可通过,但各模块 **`No tests to run`**,无自有 Java 测试 | | T-02 | 前端 `npm run build` 需 **Node ≥ 20**;v16 下 Vite 可能失败 | | T-03 | `jog-frontend/package.json` **无** `test:unit` / `test:e2e` | | N-01 | 契约、Flyway、权限等曾依赖**人工静态对比**(见 `jog-system-bug-list.md`) | --- ## 2. 测试环境与数据 | 项 | 约定 | | :--- | :--- | | JDK | 21 | | Node | ≥ 20(推荐与 CI 锁定一致) | | 集成测试 DB/Redis | Testcontainers 或隔离实例;**禁止**默认连开发者 `application.yml` 中公网地址 | | Profile | `application-test.yml`,Flyway 开启,JWT 密钥固定 | | 数据前缀 | `auto_test_*`,用例结束清理或回滚 | | 角色 | `anonymous` · `user`(`ROLE_USER`)· `admin`(`ROLE_ADMIN`) | **已知实现注记(编写断言时参考)** - 验证码接口可能为**占位**(见历史 BUG-010):只断言结构存在,不按生产级验证码验收。 - 限流 Key 可能缺 IP/用户维度(BUG-014):限流类用例标注 `weak_isolation`。 - 需求称访客可读评论;当前评论列表若在 `/api/app/comment/**`,访客可能 **401**:用例中保留 **需求差异** 断言分支。 --- ## 3. 推荐工具与落地目录 | 分层 | 工具 | 目录建议 | | :--- | :--- | :--- | | 后端单元 | JUnit 5、Mockito、AssertJ | 各模块 `src/test/java` | | 后端 API/集成 | Spring Boot Test、MockMvc、`@SpringBootTest`、Testcontainers | `jog-admin/src/test/java` 为主 | | 契约 | SpringDoc OpenAPI + 脚本对比 `jog-frontend/src/api` | `scripts/contract/` | | 前端单元 | Vitest、Vue Test Utils、MSW | `jog-frontend` | | E2E | Playwright | `e2e/` 或 `jog-frontend/e2e/` | | 性能/并发 | k6、JMeter | `perf/k6/` | | 可访问性 | axe-core + Playwright | 挂接 E2E | --- ## 4. AI 生成单条用例的强制模板 每条逻辑用例输出为一个对象(可存 `test-fixtures/*.json`): ```json { "id": "TC-AC-USER-REG-01", "title": "中文短标题", "priority": "P0|P1|P2", "trace": ["AC-USER-REG-01", "FR-USER-REG-01", "API-AUTH-003"], "layers": ["integration", "e2e"], "roles": ["anonymous"], "preconditions": ["干净库或已种子用户", "SMTP mock 或关闭发信断言"], "steps": [ { "action": "HTTP POST ...", "detail": "body 字段..." }, { "action": "查库/查 Redis", "detail": "..." } ], "expected": { "http": 200, "bodyJsonPath": { "code": 200, "data.id": "exists" }, "db": ["sys_user 新增一行 email=..."], "ui": "可选:E2E 断言" }, "negative_cases": [], "implementation_gap": null, "notes": null } ``` --- ## 5. 功能需求全量展开(对应需求 §2) 以下每节结构:**FR 覆盖表**(规则级必测点)+ **AC 详规**(验收级可执行展开)。 **API 映射列**指向附录 A 中最可能用到的路径(若尚无对应能力则写 `N/A` 并标 `implementation_gap`)。 --- ### 5.1 管理员登录(需求 §2.1) #### 5.1.1 FR → 测试要点 | FR ID | 测试要点 | 建议分层 | 优先级 | API / 备注 | | :--- | :--- | :--- | :--- | :--- | | FR-ADM-LOGIN-01 | 支持手机号+密码、用户名+密码登录 | API / E2E | P0 | `POST /api/public/admin/login` | | FR-ADM-LOGIN-02 | 仅 1 个内置超管,禁止第二管理员 | API / 集成 | P1 | 管理端用户创建接口若不存在则 `implementation_gap` | | FR-ADM-LOGIN-03 | 连续 3 次错密后需验证码;5 次错密锁定 30 分钟 | API | P0 | 结合 `GET /api/public/captcha`(占位时注明) | | FR-ADM-LOGIN-04 | 同 IP 5 分钟内失败 >10 次 → IP 封禁 15 分钟 | API / 集成 | P1 | 限流隔离弱时标 `weak_isolation` | | FR-ADM-LOGIN-05 | 每次成功/失败写登录日志:时间、IP、设备指纹、结果 | 集成 | P0 | 查 `sys_login_log` 或等价表 | | FR-ADM-LOGIN-06 | 会话 8h;记住我 7d | API / 集成 | P1 | JWT `exp`、refresh 配置 | #### 5.1.2 AC → 详规 **TC-AC-ADM-LOGIN-01**(`P0`,`trace`: AC-ADM-LOGIN-01, FR-ADM-LOGIN-01, FR-ADM-LOGIN-05) - **目的**:正确用户名或手机号 + 密码登录后台。 - **前置**:Flyway 种子管理员存在;已知凭据。 - **步骤**: 1. `POST /api/public/admin/login`,body:账号字段(与实现一致)、密码、可选 `deviceFingerprint`。 2. 断言 200,`data` 含访问令牌与管理员信息。 3. 数据库/日志:`result=成功`、IP/时间非空。 - **E2E**:登录表单提交后 URL 进入 `/admin` 或仪表盘路由。 - **api_ref**:附录 A `AuthController`。 **TC-AC-ADM-LOGIN-02**(`P0`,`trace`: AC-ADM-LOGIN-02, FR-ADM-LOGIN-03) - **目的**:连续 3 次错误密码后第 4 次需验证码。 - **步骤**: 1. 同一账号连续 3 次错误密码。 2. 第 4 次请求:不带验证码 → 期望 400/422 或业务码提示需验证码(与实现一致)。 3. `GET /api/public/captcha` 取 `captchaKey`;带正确/错误验证码各测一轮。 - **implementation_gap**:若验证码为占位,则断言「接口返回结构」+ 业务仍返回需验证码 **或** 记录产品与实现对齐缺口。 **TC-AC-ADM-LOGIN-03**(`P0`,`trace`: AC-ADM-LOGIN-03, FR-ADM-LOGIN-03) - **目的**:连续 5 次错误锁定 30 分钟。 - **步骤**:连续失败至阈值;第 6 次正确密码仍不可登录;期望文案含锁定与约 30 分钟。 - **集成**:查用户 `locked_until` 或等价字段。 **TC-AC-ADM-LOGIN-04**(`P1`,`trace`: AC-ADM-LOGIN-04, FR-ADM-LOGIN-02) - **目的**:禁止第二超级管理员。 - **步骤**:若存在「创建管理员」API 则调用并期望拒绝;若无 API 则静态断言 `user_type` 枚举与注册路径不通。 **TC-AC-ADM-LOGIN-05**(`P0`,`trace`: AC-ADM-LOGIN-05, FR-ADM-LOGIN-05) - **目的**:登录日志字段完整。 - **步骤**:成功一次、失败一次;查日志表:`ip`、`device`/`ua`、`result`、`time`。 --- ### 5.2 用户注册(需求 §2.2) #### 5.2.1 FR → 测试要点 | FR ID | 测试要点 | 建议分层 | 优先级 | | :--- | :--- | :--- | :--- | | FR-USER-REG-01 | 邮箱+密码必填 | API / FE 单元 | P0 | | FR-USER-REG-02 | 密码 8~32 且至少三类字符 | FE + API | P0 | | FR-USER-REG-03 | 邮箱唯一;发验证邮件 | API / 集成 | P0 | | FR-USER-REG-04 | 验证链接 24h | API | P1 | | FR-USER-REG-05 | 同 IP 1h 最多 3 次注册 | API | P0 | | FR-USER-REG-06 | 无自助找回;仅管理员重置 | API | P1 | #### 5.2.2 AC → 详规 **TC-AC-USER-REG-01**(`P0`,`trace`: AC-USER-REG-01, FR-USER-REG-01~03) - **步骤**:合法邮箱+合规密码 `POST /api/public/user/register` → 200;DB 用户存在;邮件发送可 mock 断言「调用次数」。 **TC-AC-USER-REG-02**(`P0`,`trace`: AC-USER-REG-02, FR-USER-REG-03) - **步骤**:重复邮箱第二次注册 → 业务错误「该邮箱已被注册」或等价码。 **TC-AC-USER-REG-03**(`P0`,`trace`: AC-USER-REG-03, FR-USER-REG-02) - **步骤**:纯数字或少于 8 位 → 前端校验拦截;绕过前端直调 API → 400/业务错误。 **TC-AC-USER-REG-04**(`P0`,`trace`: AC-USER-REG-04, FR-USER-REG-05) - **步骤**:同 IP(或同测试标识)第 4 次注册 → 限流或「注册过于频繁」。 **TC-AC-USER-REG-05**(`P0`,`trace`: AC-USER-REG-05, FR-USER-REG-06) - **步骤**:管理员 `PUT /api/admin/user/{id}/reset-password`;旧密码失效、新密码可登录。 #### 5.2.3 FR 补充用例(无独立 AC) **TC-FR-USER-REG-04**(`P1`,`trace`: FR-USER-REG-04) - **目的**:邮箱验证 token 超过 24h 失效。 - **步骤**:插入过期 token 或时钟模拟;请求验证接口期望失败。 --- ### 5.3 用户登录(需求 §2.3) #### 5.3.1 FR → 测试要点 | FR ID | 测试要点 | 优先级 | | :--- | :--- | :--- | | FR-USER-LOGIN-01 | 邮箱+密码 | P0 | | FR-USER-LOGIN-02 | 最多 3 活跃会话,驱逐最早 | P0 | | FR-USER-LOGIN-03 | OAuth 扩展点可配置开关 | P2 | | FR-USER-LOGIN-04 | 5 次错密锁定 15 分钟 | P0 | | FR-USER-LOGIN-05 | 忘记密码引导联系管理员 | P1 | | FR-USER-LOGIN-06 | 默认 24h;记住我 14d | P0 | #### 5.3.2 AC → 详规 **TC-AC-USER-LOGIN-01**(`P0`,`trace`: AC-USER-LOGIN-01) - `POST /api/public/user/login` 成功;返回 Token 与用户信息。 **TC-AC-USER-LOGIN-02**(`P0`,`trace`: AC-USER-LOGIN-02, FR-USER-LOGIN-02) - 模拟 4 个客户端(不同 `deviceFingerprint` 或 User-Agent):第 4 次登录后,最早 Token 调受保护接口 **401/失效**。 **TC-AC-USER-LOGIN-03**(`P0`,`trace`: AC-USER-LOGIN-03, FR-USER-LOGIN-04) - 连续 5 次错误密码 → 锁定 15 分钟;比对管理员锁定时长差异(需求管理员 30min / 用户 15min)。 **TC-AC-USER-LOGIN-04**(`P1`,`trace`: AC-USER-LOGIN-04, FR-USER-LOGIN-05) - E2E:点击忘记密码 → 文案含联系管理员。 **TC-AC-USER-LOGIN-05**(`P2`,`trace`: AC-USER-LOGIN-05, FR-USER-LOGIN-03) - 配置项 OAuth 开关存在;`/api/oauth/**` 或配置表中开关读取断言。 **TC-AC-USER-LOGIN-06**(`P0`,`trace`: AC-USER-LOGIN-06, FR-USER-LOGIN-06) - 记住我勾选:`refresh`/Cookie 过期时间接近 14d;未勾选接近 24h(按实现字段断言)。 --- ### 5.4 博客发布(需求 §2.4) #### 5.4.1 FR → 测试要点 | FR ID | 测试要点 | 优先级 | | :--- | :--- | :--- | | FR-BLOG-PUB-01 | 未登录不可编辑 | P0 | | FR-BLOG-PUB-02 | 富文本、图片格式与大小、视频嵌入 | P0/P1 | | FR-BLOG-PUB-03 | 手动存草稿 + 30s 自动保存 | P1 | | FR-BLOG-PUB-04 | 可见性:公开/私密/仅粉丝 | P0 | | FR-BLOG-PUB-05 | 已发布可改可见性即时生效 | P0 | | FR-BLOG-PUB-06 | 必选 1 分类、≤5 标签 | P0 | | FR-BLOG-PUB-07 | XSS 过滤;禁止非图上传 | P0 | #### 5.4.2 AC → 详规 **TC-AC-BLOG-PUB-01**(`P0`,`trace`: AC-BLOG-PUB-01, FR-BLOG-PUB-01) - E2E:直接打开编辑路由 → 重定向登录;`redirect` 回跳。 **TC-AC-BLOG-PUB-02**(`P1`,`trace`: AC-BLOG-PUB-02, FR-BLOG-PUB-02) - E2E/API:插入图片 URL 或上传接口;超限文件失败。 **TC-AC-BLOG-PUB-03**(`P1`,`trace`: AC-BLOG-PUB-03, FR-BLOG-PUB-03) - 保存草稿后再进入编辑;内容一致;若有自动保存接口则 mock 时钟测 30s(或文档说明降常为 P2)。 **TC-AC-BLOG-PUB-04**(`P0`,`trace`: AC-BLOG-PUB-04, FR-BLOG-PUB-04) - 作者可见私密文;访客 `GET /api/public/article/{id}` → 404 或无权。 **TC-AC-BLOG-PUB-05**(`P0`,`trace`: AC-BLOG-PUB-05, FR-BLOG-PUB-05) - `PUT /api/app/article/{id}` 改可见性后,访客再看详情变化。 **TC-AC-BLOG-PUB-06**(`P0`,`trace`: AC-BLOG-PUB-06, FR-BLOG-PUB-06) - 创建携带 6 个 tagId → 拒绝。 **TC-AC-BLOG-PUB-07**(`P0`,`trace`: AC-BLOG-PUB-07, FR-BLOG-PUB-07) - 上传 `.exe` 或使用文章正文带可执行链接策略;期望拒绝或清洗。 --- ### 5.5 博客列表查看(需求 §2.5) #### 5.5.1 FR → 测试要点 | FR ID | 测试要点 | 优先级 | | :--- | :--- | :--- | | FR-BLOG-LIST-01 | 按发布时间升降序、浏览量降序 | P0 | | FR-BLOG-LIST-02 | 分类 + 标签组合筛选 | P0 | | FR-BLOG-LIST-03 | 标题+正文全文检索与高亮(UI) | P0 | | FR-BLOG-LIST-04 | 每页 15 条 | P0 | | FR-BLOG-LIST-05 | 私密只对作者列表可见 | P0 | | FR-BLOG-LIST-06 | 仅粉丝可见:作者+粉丝 | P0 | | FR-BLOG-LIST-07 | 浏览量:访客/用户去重;作者本人不看加 | P0 | | FR-BLOG-LIST-08 | 卡片展示阅读量 | P1 | #### 5.5.2 AC → 详规 **TC-AC-BLOG-LIST-01**(`P0`,`trace`: AC-BLOG-LIST-01, FR-BLOG-LIST-01) - `GET /api/public/article/list` 带 `sortBy`/`order`(以代码参数名为准);断言顺序。 **TC-AC-BLOG-LIST-02**(`P0`,`trace`: AC-BLOG-LIST-02, FR-BLOG-LIST-02) - 同时 `categoryId` + `tagId`;结果集同时满足。 **TC-AC-BLOG-LIST-03**(`P0`,`trace`: AC-BLOG-LIST-03, FR-BLOG-LIST-03) - 关键字搜索;E2E 断言高亮 DOM 或 API 返回摘要含关键词。 **TC-AC-BLOG-LIST-04**(`P0`,`trace`: AC-BLOG-LIST-04, FR-BLOG-LIST-04) - **说明**:需求原文写「第 3 页」,按 **第 2 页** 语义理解为分页;请求 `page=2`,`pageSize=15`,本页最多 15 条,`total` 与页码一致。 **TC-AC-BLOG-LIST-05**(`P0`,`trace`: AC-BLOG-LIST-05, FR-BLOG-LIST-05) - 作者列表可见私密文;其他用户列表不可见。 **TC-AC-BLOG-LIST-06**(`P0`,`trace`: AC-BLOG-LIST-06, FR-BLOG-LIST-07) - 作者访问本人详情:`view_count` 两次请求不变(或增量为 0)。 **TC-AC-BLOG-LIST-07**(`P1`,`trace`: AC-BLOG-LIST-07, FR-BLOG-LIST-08) - E2E:列表卡片渲染 `viewCount` 字段非空且与接口一致。 #### 5.5.3 FR 补充 **TC-FR-BLOG-LIST-06**(`P0`,`trace`: FR-BLOG-LIST-06) - 用户 B 关注作者 A 后可见「仅粉丝可见」文;未关注则不可见。 --- ### 5.6 评论功能(需求 §2.6) #### 5.6.1 FR → 测试要点 | FR ID | 测试要点 | 优先级 | | :--- | :--- | :--- | | FR-COMMENT-01 | 登录才能评;访客可读 | P0 | | FR-COMMENT-02 | 最多 3 级;更深变平级 | P0 | | FR-COMMENT-03 | 审核开关 | P0 | | FR-COMMENT-04 | 作者标识 | P1 | | FR-COMMENT-05 | 管理员删/屏蔽 | P0 | | FR-COMMENT-06 | 回复站内通知 | P1 | | FR-COMMENT-07 | XSS + 敏感词 | P0 | #### 5.6.2 AC → 详规 **TC-AC-COMMENT-01**(`P0`,`trace`: AC-COMMENT-01, FR-COMMENT-01) - E2E:未登录点发表 → 登录引导。 - **API 差异**:访客调评论列表若需登录,记 `implementation_gap` 相对 FR-COMMENT-01「访客可读」。 **TC-AC-COMMENT-02**(`P0`,`trace`: AC-COMMENT-02, FR-COMMENT-02) - 构造 A→B→C→D 四级;断言 D 与 C 平级 `level`/结构。 **TC-AC-COMMENT-03**(`P0`,`trace`: AC-COMMENT-03, FR-COMMENT-03) - 开关开启:`POST` 评论后前台列表无;管理员 `PUT /api/admin/comment/{id}/audit` 后可见。 **TC-AC-COMMENT-04**(`P1`,`trace`: AC-COMMENT-04, FR-COMMENT-04) - 作者账号评论:`isAuthor` 或 UI 徽章。 **TC-AC-COMMENT-05**(`P0`,`trace`: AC-COMMENT-05, FR-COMMENT-05) - 屏蔽后:其它用户不可见;发表者可见(按实现 status)。 **TC-AC-COMMENT-06**(`P1`,`trace`: AC-COMMENT-06, FR-COMMENT-06) - A 回复 B 后 B 的通知列表/未读数+1(若未实现则 `implementation_gap`)。 **TC-AC-COMMENT-07**(`P0`,`trace`: AC-COMMENT-07, FR-COMMENT-07) - 评论含 `