4e21ca937a
Deploy Documentation / deploy (push) Has been cancelled
Canary / Prepare Version (push) Has been cancelled
Canary / build-cli (push) Has been cancelled
Canary / Upload Install Script (push) Has been cancelled
Canary / bundle-desktop (push) Has been cancelled
Canary / bundle-desktop-intel (push) Has been cancelled
Canary / bundle-desktop-linux (push) Has been cancelled
Canary / bundle-desktop-windows (push) Has been cancelled
Canary / bundle-desktop-windows-cuda (push) Has been cancelled
Canary / Release (push) Has been cancelled
Unused Dependencies / machete (push) Has been cancelled
CI / changes (push) Has been cancelled
CI / Check Rust Code Format (push) Has been cancelled
CI / Build and Test Rust Project (push) Has been cancelled
CI / Build Rust Project on Windows (push) Has been cancelled
CI / Check MSRV (push) Has been cancelled
CI / Lint Rust Code (push) Has been cancelled
CI / Check Generated Schemas are Up-to-Date (push) Has been cancelled
CI / Test and Lint Electron Desktop App (push) Has been cancelled
CI / H5 Plaza Tests and Build (push) Has been cancelled
Live Provider Tests / check-fork (push) Has been cancelled
Live Provider Tests / changes (push) Has been cancelled
Live Provider Tests / Build Binary (push) Has been cancelled
Live Provider Tests / Smoke Tests (push) Has been cancelled
Live Provider Tests / Smoke Tests (Code Execution) (push) Has been cancelled
Live Provider Tests / Compaction Tests (push) Has been cancelled
Live Provider Tests / goose server HTTP integration tests (push) Has been cancelled
Publish Ask AI Bot Docker Image / docker (push) Has been cancelled
Publish Docker Image / docker (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Fork goose with custom MCP widgets, platform extensions (aider, git, web, search), MindSpace H5 backend/frontend, Plaza/Ops UIs, and deploy scripts for tkmind.cn. Co-authored-by: Cursor <cursoragent@cursor.com>
278 lines
8.4 KiB
Markdown
278 lines
8.4 KiB
Markdown
---
|
||
sidebar_position: 10
|
||
title: 测试要求
|
||
sidebar_label: 测试要求
|
||
description: Plaza 的自动化测试策略、权限矩阵、E2E 场景、性能基准和验收标准
|
||
---
|
||
|
||
# 测试要求
|
||
|
||
## 测试策略
|
||
|
||
```text
|
||
E2E 测试(Playwright) 覆盖核心用户流程
|
||
│
|
||
集成测试(真实 DB + Redis) 覆盖 API 契约和权限矩阵
|
||
│
|
||
单元测试 覆盖热度算法、格式化函数、状态机
|
||
```
|
||
|
||
所有测试必须使用真实数据库连接,不允许 Mock DB(与 MindSpace 测试策略一致)。
|
||
|
||
---
|
||
|
||
## 权限矩阵
|
||
|
||
每个 API 必须测试以下角色的访问结果:
|
||
|
||
| 接口 | 游客 | 普通用户(非作者) | 作者本人 | 运营人员 |
|
||
| --- | --- | --- | --- | --- |
|
||
| GET /feed | 200 ✅ | 200 ✅ | 200 ✅ | 200 ✅ |
|
||
| GET /posts/:id | 200 ✅ | 200 ✅ | 200 ✅ | 200 ✅ |
|
||
| POST /posts(发布到广场) | 401 ❌ | 200 ✅ | 200 ✅ | 200 ✅ |
|
||
| DELETE /posts/:id | 401 ❌ | 403 ❌ | 200 ✅ | - |
|
||
| POST /posts/:id/reactions | 401 ❌ | 200 ✅ | 200 ✅ | 200 ✅ |
|
||
| POST /posts/:id/comments | 401 ❌ | 200 ✅ | 200 ✅ | 200 ✅ |
|
||
| DELETE /comments/:id(他人评论) | 401 ❌ | 403 ❌ | 403 ❌ | - |
|
||
| DELETE /comments/:id(自己评论) | 401 ❌ | 200 ✅ | 200 ✅ | - |
|
||
| POST /users/:slug/follow(关注自己) | 401 ❌ | - | 422 ❌ | - |
|
||
| POST /ops/review/posts/:id | 401 ❌ | 403 ❌ | 403 ❌ | 200 ✅ |
|
||
| GET /ops/analytics | 401 ❌ | 403 ❌ | 403 ❌ | 200 ✅ |
|
||
|
||
---
|
||
|
||
## 必测 API 场景
|
||
|
||
### 发布到广场
|
||
|
||
```
|
||
✅ 正常发布:publication online → 创建 plaza_posts status=pending_review
|
||
✅ publication 不是 online 状态 → 422 PUBLICATION_NOT_ONLINE
|
||
✅ 同一 publication 重复 POST → 409 ALREADY_PUBLISHED
|
||
✅ 同一 publication 更新元数据 → PATCH /posts/:id 成功
|
||
✅ publication 归属其他用户 → 403
|
||
✅ 用户被封禁发帖权限 → 403 POST_PERMISSION_DENIED
|
||
✅ 下线 publication 后,对应 plaza_posts status 自动变为 hidden
|
||
```
|
||
|
||
### Feed 接口
|
||
|
||
```
|
||
✅ 默认返回 hot 排序
|
||
✅ sort=new 返回按 published_at 倒序
|
||
✅ 按 category slug 筛选只返回该分类帖子
|
||
✅ 游客请求 viewer_reacted 字段为 null
|
||
✅ 登录用户请求 viewer_reacted 正确反映点赞/收藏状态
|
||
✅ status=pending_review 和 hidden 的帖子不出现在 feed 中
|
||
✅ 游标翻页不重复、不遗漏
|
||
```
|
||
|
||
### 点赞
|
||
|
||
```
|
||
✅ 点赞成功 → plaza_posts.like_count +1(经 Redis → MySQL 同步后)
|
||
✅ 重复点赞 → 幂等,返回 200,计数不重复增加
|
||
✅ 取消点赞 → 计数 -1,不出现负数
|
||
✅ 取消未点赞的帖子 → 404 或 204(幂等)
|
||
```
|
||
|
||
### 评论
|
||
|
||
```
|
||
✅ 发表一级评论 → comment_count +1
|
||
✅ 发表二级回复 → 父评论 reply_count +1
|
||
✅ 三级嵌套(parent_id 指向二级评论)→ 422 REPLY_DEPTH_EXCEEDED
|
||
✅ 对关闭评论的帖子发评论 → 422 COMMENT_DISABLED
|
||
✅ 评论超过 500 字符 → 422
|
||
✅ 软删除评论 → content 为空,status=deleted,reply_count 保留
|
||
✅ 帖子删除(status=hidden)后,已有评论不暴露给公开接口
|
||
```
|
||
|
||
### 关注
|
||
|
||
```
|
||
✅ 关注他人 → follower_count / following_count 各 +1(事务内)
|
||
✅ 取消关注 → -1
|
||
✅ 关注自己 → 422 SELF_FOLLOW
|
||
✅ 重复关注 → 幂等返回 200,计数不重复
|
||
```
|
||
|
||
### 运营审核
|
||
|
||
```
|
||
✅ 审核通过 → status=published,写入 ops_audit_log
|
||
✅ 拒绝 → status=rejected,必须有 reason,发送通知
|
||
✅ 隐藏 → status=hidden,帖子从 feed 消失
|
||
✅ 普通用户调用审核接口 → 403 OPS_PERMISSION_DENIED
|
||
✅ 审核日志不可修改(不提供 UPDATE/DELETE 接口)
|
||
```
|
||
|
||
---
|
||
|
||
## 热度算法测试
|
||
|
||
```
|
||
✅ 新帖 hot_score = 0(无互动,发布即刻)
|
||
✅ 相同互动量、发布时间越早 hot_score 越低(时间衰减验证)
|
||
✅ 修改 plaza_algorithm_config 权重后,下次计算周期生效
|
||
✅ hot_score 不出现负数
|
||
✅ 大量帖子(1000 条)批量计算完成时间 < 5 秒
|
||
```
|
||
|
||
---
|
||
|
||
## 数据一致性测试
|
||
|
||
```
|
||
✅ 配额预留和确认在同一事务(从 MindSpace 继承,无需新测)
|
||
✅ 关注关系表 UNIQUE 约束:并发关注不产生重复行
|
||
✅ 点赞 UNIQUE 约束:并发点赞不超过 1 条记录
|
||
✅ 发布到广场 UNIQUE(publication_id):并发请求不产生重复帖子
|
||
✅ publication 下线事务:plaza_posts 同步隐藏在同一事务内完成
|
||
```
|
||
|
||
---
|
||
|
||
## E2E 场景(Playwright)
|
||
|
||
### 场景 1:完整发布流程
|
||
|
||
```
|
||
1. 用户 A 登录 MindSpace
|
||
2. 发布一个 MindSpace 页面(publication online)
|
||
3. 点击「发布到广场」
|
||
4. 选择分类「职场报告」,输入标签「复盘」
|
||
5. 确认发布
|
||
6. 验证:/plaza 首页最新列表出现该帖子
|
||
7. 验证:curl /plaza/p/{id} 的 HTML 包含帖子标题(SSR 验证)
|
||
```
|
||
|
||
### 场景 2:互动完整流程
|
||
|
||
```
|
||
1. 游客打开帖子详情 /plaza/p/{id}
|
||
2. 点击点赞 → 弹出登录引导浮层
|
||
3. 游客登录
|
||
4. 登录后自动回到帖子详情,点赞成功
|
||
5. 刷新页面,点赞状态保持(viewer_reacted.liked = true)
|
||
6. 点击取消点赞,状态恢复
|
||
```
|
||
|
||
### 场景 3:评论和回复
|
||
|
||
```
|
||
1. 用户 A 在帖子下发表评论「很好!」
|
||
2. 用户 B 登录后回复「+1」
|
||
3. 验证:评论区展示 A 的评论,B 的回复在其下方
|
||
4. A 删除自己的评论
|
||
5. 验证:评论显示「该评论已删除」,B 的回复仍然可见
|
||
6. 尝试三级嵌套 → 前端禁用回复按钮
|
||
```
|
||
|
||
### 场景 4:运营审核
|
||
|
||
```
|
||
1. 用户发布帖子到广场,status=pending_review
|
||
2. 游客访问 /plaza,该帖子不可见
|
||
3. 运营人员登录 /ops/review
|
||
4. 点击「通过」审核
|
||
5. 验证:帖子在广场首页可见
|
||
6. 验证:ops_audit_log 有一条记录
|
||
```
|
||
|
||
### 场景 5:越权访问
|
||
|
||
```
|
||
1. 用户 A 发布帖子到广场
|
||
2. 用户 B 尝试 DELETE /api/plaza/v1/posts/{A的帖子id}
|
||
3. 验证:返回 403
|
||
4. 用户 B 尝试发布用户 A 的 publication → 返回 403
|
||
5. 游客尝试发表评论 → 返回 401
|
||
```
|
||
|
||
### 场景 6:SEO 验证
|
||
|
||
```
|
||
1. 发布一个帖子到广场
|
||
2. curl -A "Googlebot" https://go.tkmind.cn/plaza/p/{id}
|
||
3. 验证响应 HTML 中包含:
|
||
- <title> 标签含帖子标题
|
||
- <meta property="og:title">
|
||
- <meta property="og:image">
|
||
- <meta property="og:description">
|
||
- <script type="application/ld+json"> Article schema
|
||
4. curl https://go.tkmind.cn/sitemap.xml
|
||
5. 验证帖子 URL 出现在 sitemap 中
|
||
```
|
||
|
||
### 场景 7:publication 下线联动
|
||
|
||
```
|
||
1. 帖子在广场正常展示(status=published)
|
||
2. 作者在 MindSpace 将 publication 下线
|
||
3. 验证:plaza_posts.status 自动变为 hidden
|
||
4. 验证:/plaza feed 中该帖子消失
|
||
5. 验证:直接访问 /plaza/p/{id} 返回 404
|
||
```
|
||
|
||
---
|
||
|
||
## 性能基准
|
||
|
||
在测试环境(单机 2C4G)满足:
|
||
|
||
| 接口 | p50 | p99 | 说明 |
|
||
| --- | --- | --- | --- |
|
||
| GET /feed(第一页,冷缓存) | < 200ms | < 500ms | MySQL 查询 |
|
||
| GET /feed(命中 Redis 缓存) | < 30ms | < 100ms | 缓存读取 |
|
||
| GET /posts/:id | < 100ms | < 300ms | |
|
||
| POST /posts/reactions | < 100ms | < 300ms | Redis INCR |
|
||
| POST /posts/comments | < 150ms | < 400ms | MySQL 写入 |
|
||
| 热度计算(1000 帖子) | < 5s | - | 定时任务 |
|
||
| Next.js SSR(帖子详情) | < 300ms | < 800ms | 含 API 调用 |
|
||
|
||
---
|
||
|
||
## 前端测试
|
||
|
||
```bash
|
||
# Plaza Next.js
|
||
cd ui/plaza
|
||
pnpm test # Jest 单元测试
|
||
pnpm e2e # Playwright E2E
|
||
|
||
# 测试文件位置
|
||
ui/plaza/__tests__/
|
||
api.test.ts # API 封装函数测试
|
||
format.test.ts # 数字格式化测试
|
||
algorithm.test.ts # hot_score 公式验证(前端展示用)
|
||
|
||
ui/plaza/e2e/
|
||
publish-flow.spec.ts # 发布完整流程
|
||
interaction.spec.ts # 互动场景
|
||
seo.spec.ts # SSR 和 meta 验证
|
||
```
|
||
|
||
---
|
||
|
||
## CI 检查清单
|
||
|
||
每个 PR 合并前 CI 必须通过:
|
||
|
||
```
|
||
□ pnpm build(ui/plaza、ui/ops)— h5-plaza job
|
||
□ 后端测试:node --test ui/h5/plaza-*.test.mjs(含 MySQL 集成,CI 提供 MySQL 8 服务)
|
||
□ just check-h5-openapi-schema(Plaza/Ops 路由已纳入 ui/h5/openapi.json)
|
||
□ E2E:core 场景(场景 1-4)— 待 Playwright 落地
|
||
□ 新的 SQL 迁移文件可在空库执行(initSchema + plaza-integration 覆盖)
|
||
□ 新的 SQL 迁移文件可在含现有数据的库执行(db.mjs ALTER 幂等)
|
||
```
|
||
|
||
本地运行集成测试:
|
||
|
||
```bash
|
||
# 需 MySQL(或 CI 同款环境变量)
|
||
export MYSQL_HOST=127.0.0.1 MYSQL_USER=root MYSQL_PASSWORD=... MYSQL_DATABASE=...
|
||
cd ui/h5 && node --test plaza-integration.test.mjs
|
||
```
|