# AI 有声书 - 测试指南

## 测试架构概览

```
tests/
├── unit/                    # 单元测试 (Vitest)
│   ├── setup.ts            # 全局测试配置
│   ├── mocks/              # Mock 工厂
│   │   ├── llm.mock.ts
│   │   ├── tts.mock.ts
│   │   └── payment.mock.ts
│   └── backend/services/   # 后端服务单元测试
│       ├── tts/
│       │   ├── circuit-breaker.test.ts
│       │   └── provider-registry.test.ts
│       ├── subscription/
│       │   └── subscription.service.test.ts
│       ├── book-generator/
│       │   ├── stage-manager.test.ts
│       │   └── book-type-config.test.ts
│       └── payment/
│           └── payment.service.test.ts
│
├── integration/            # 集成测试 (Vitest)
│   ├── api/
│   │   ├── auth-flow.test.ts
│   │   ├── book-generator-flow.test.ts
│   │   ├── payment-flow.test.ts
│   │   ├── tts-flow.test.ts
│   │   ├── subscription-flow.test.ts
│   │   └── publish-flow.test.ts
│   ├── db/
│   │   └── prisma-crud.test.ts
│   └── http-client.ts     # 集成测试专用 HTTP 客户端 (axios)
│
├── e2e/ui/critical-journeys/  # 关键旅程 E2E (Playwright)
│   ├── journey-01-register-login.spec.ts
│   ├── journey-02-free-tts.spec.ts
│   ├── journey-03-book-generate.spec.ts
│   ├── journey-04-subscribe-play.spec.ts
│   └── journey-05-publish.spec.ts
│
├── regression/             # 回归测试 (Playwright)
├── smoke/                  # 冒烟测试 (Playwright)
├── helpers/                # 测试工具
│   ├── api-client.ts
│   └── test-data.ts
├── playwright.config.ts     # Playwright 配置
└── vitest.config.mts        # Vitest 配置（统一单元+集成测试）
```

## 快速开始

### 1. 安装依赖

```bash
cd server && npm install
cd .. && npm install
npx playwright install --with-deps chromium
```

### 2. 运行所有测试

```bash
# 单元测试 + 集成测试 (Vitest)
cd server && npm run test:unit

# 关键旅程 E2E (需启动服务器)
npx playwright test --project=critical-journeys --config=tests/playwright.config.ts

# 全部回归测试
npx playwright test --project=regression --config=tests/playwright.config.ts
```

---

## 详细使用指南

### 单元测试 (Vitest)

**位置**: `tests/unit/`

**运行命令**:

```bash
cd server

# 运行所有单元测试
npm run test:unit

# 监听模式 (文件变化自动重新测试)
npm run test:unit:watch

# 生成覆盖率报告
npm run test:coverage
```

**覆盖模块**:

| 文件 | 覆盖模块 | 测试数 |
|------|----------|--------|
| `circuit-breaker.test.ts` | 熔断器状态机 | 21 |
| `provider-registry.test.ts` | TTS 提供商注册 | 28 |
| `subscription.service.test.ts` | 订阅配额计算 | 24 |
| `stage-manager.test.ts` | 书籍生成状态机 | 23 |
| `book-type-config.test.ts` | 书籍类型配置 | 41 |
| `payment.service.test.ts` | 支付服务 | 11 |
| **总计** | | **148** |

**覆盖率阈值**:

```yaml
全局: statements 80%, branches 70%
subscription: statements 95%, branches 90%
tts: statements 90%, branches 85%
payment: statements 90%, branches 85%
book-generator: statements 75%, branches 65%
circuit-breaker: statements 90%, branches 85%
```

---

### 集成测试 (Vitest)

**位置**: `tests/integration/`

**前置条件**: MySQL 数据库 (默认 `mysql://root:@localhost:3307/audio_book_test`)

**运行命令**:

```bash
cd server

# 设置数据库 URL (可选，默认使用环境变量)
export TEST_DATABASE_URL="mysql://root:password@localhost:3307/audio_book_test"

# 运行所有集成测试
npx vitest run --config vitest.config.mts tests/integration

# 运行特定集成测试
npx vitest run --config vitest.config.mts tests/integration/api/auth-flow.test.ts
npx vitest run --config vitest.config.mts tests/integration/db/prisma-crud.test.ts
```

**测试文件**:

| 文件 | 覆盖流程 |
|------|----------|
| `auth-flow.test.ts` | 发送验证码 → 登录 → Token 刷新 |
| `book-generator-flow.test.ts` | 预估 → 检测类型 → 创建 → 进度 |
| `payment-flow.test.ts` | 下单 → 支付回调 → 会员更新 |
| `tts-flow.test.ts` | 合成 → 存储 → 配额扣除 |
| `subscription-flow.test.ts` | 套餐切换 → 配额计算 → 超额 |
| `publish-flow.test.ts` | 发布 → 可见性 |
| `prisma-crud.test.ts` | User/Book/Chapter CRUD + 事务 |

**数据库设置**:

```bash
# 创建测试数据库
mysql -u root -e "CREATE DATABASE IF NOT EXISTS audio_book_test;"

# 初始化表结构
cd server && npx prisma db push --skip-generate
```

---

### 关键旅程 E2E (Playwright)

**位置**: `tests/e2e/ui/critical-journeys/`

**前置条件**: 服务器运行在 `http://localhost:3000`

**运行命令**:

```bash
cd /c/Users/caoyg/ai/audio-tts/audio_codebuddy

# 启动服务器 (终端 1)
cd server && npm run dev &

# 等待服务器就绪 (终端 2)
# 验证服务器可用
curl http://localhost:3000

# 运行关键旅程测试
npx playwright test --project=critical-journeys --config=tests/playwright.config.ts

# 运行特定旅程
npx playwright test --project=critical-journeys journey-01-register-login --config=tests/playwright.config.ts
```

**关键旅程清单**:

| Journey | 文件 | 测试场景 |
|---------|------|----------|
| C01 | `journey-01-register-login.spec.ts` | 注册 → 登录 → Token 获取 → 首页访问 |
| C02 | `journey-02-free-tts.spec.ts` | 音色列表 → 生成音频 → 状态查询 → 播放页访问 |
| C03 | `journey-03-book-generate.spec.ts` | 预估 → 类型检测 → 创建书籍 → 章节列表 |
| C04 | `journey-04-subscribe-play.spec.ts` | 套餐列表 → 下单 → 支付回调 → 会员等级验证 |
| C05 | `journey-05-publish.spec.ts` | 创建书籍 → 发布 → 列表验证 → 可见性确认 |

**总计**: 35 个测试

---

### 回归测试 (Playwright)

**位置**: `tests/regression/`

**运行命令**:

```bash
cd /c/Users/caoyg/ai/audio-tts/audio_codebuddy

# 确保服务器运行
cd server && npm run dev &

# 运行所有回归测试
npx playwright test --project=regression --config=tests/playwright.config.ts

# 运行特定回归测试
npx playwright test --project=regression 01-auth --config=tests/playwright.config.ts
```

**测试文件**:

| 文件 | 模块 |
|------|------|
| `01-auth.spec.ts` | 认证模块 |
| `02-tts.spec.ts` | TTS 语音合成 |
| `03-player.spec.ts` | 播放器 |
| `04-favorites.spec.ts` | 收藏 |
| `05-history.spec.ts` | 历史记录 |
| `06-search.spec.ts` | 搜索 |
| `07-comments.spec.ts` | 评论 |
| `08-notifications.spec.ts` | 通知 |
| `09-bgm.spec.ts` | BGM |
| `10-audio-edit.spec.ts` | 音频编辑 |
| `11-book-generator.spec.ts` | 书籍生成 |
| `12-album.spec.ts` | 专辑 |
| `13-playlists.spec.ts` | 播放列表 |
| `17-publish.spec.ts` | 发布 |
| `23-frontend-e2e.spec.ts` | 前端 UI 验收 |

---

### 冒烟测试 (Playwright)

**位置**: `tests/smoke/`

**运行命令**:

```bash
# 最快的测试子集，用于快速验证
npx playwright test --project=smoke --config=tests/playwright.config.ts
```

---

## CI/CD 集成

### GitHub Actions 工作流

**`.github/workflows/unit-test.yml`** - Push/PR 时自动运行单元测试

```yaml
on: [push, pull_request]
jobs:
  unit-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: Install & Test
        run: |
          cd server && npm ci
          npm run test:unit
```

**`.github/workflows/e2e-test.yml`** - E2E 测试 (需要服务器运行)

**`.github/workflows/integration-test.yml`** - 集成测试 (需要 MySQL)

---

## 环境变量

| 变量 | 默认值 | 说明 |
|------|--------|------|
| `TEST_DATABASE_URL` | `mysql://root:@localhost:3307/audio_book_test` | 集成测试数据库 |
| `FRONTEND_URL` | `http://localhost:5173` | 前端 URL (E2E 测试) |
| `BASE_URL` | `http://localhost:3000` | 后端 API URL |
| `START_SERVER` | `true` | 是否自动启动服务器 (Playwright) |

---

## 故障排查

### 单元测试失败

```bash
# 清理缓存后重试
cd server && rm -rf node_modules/.vite && npm run test:unit

# 查看详细输出
npx vitest run --config vitest.config.mts --reporter=verbose
```

### 集成测试失败 (数据库)

```bash
# 检查数据库连接
mysql -u root -e "SELECT 1;"

# 重新初始化数据库
mysql -u root -e "DROP DATABASE IF EXISTS audio_book_test; CREATE DATABASE audio_book_test;"
cd server && npx prisma db push
```

### E2E 测试失败 (服务器未运行)

```bash
# 检查服务器状态
curl http://localhost:3000

# 重启服务器
cd server && pkill -f "tsx" && npm run dev &
sleep 10
```

---

## 测试覆盖率报告

```bash
# 生成 HTML 覆盖率报告
cd server && npm run test:coverage

# 查看报告
open ../coverage/index.html
```

报告位置: `server/coverage/index.html`

---

## 常用命令速查表

```bash
# === 单元测试 ===
cd server && npm run test:unit           # 运行所有单元测试
cd server && npm run test:unit:watch     # 监听模式
cd server && npm run test:coverage       # 生成覆盖率

# === 集成测试 ===
export TEST_DATABASE_URL="mysql://root:password@localhost:3307/audio_book_test"
cd server && npx vitest run --config vitest.config.mts tests/integration

# === Playwright E2E ===
cd server && npm run dev &               # 启动服务器
sleep 10
npx playwright test --project=smoke --config=tests/playwright.config.ts            # 冒烟测试
npx playwright test --project=critical-journeys --config=tests/playwright.config.ts # 关键旅程
npx playwright test --project=regression --config=tests/playwright.config.ts       # 回归测试
npx playwright test --config=tests/playwright.config.ts                             # 全部 E2E

# === 查看报告 ===
npx playwright show-report tests/test-results/report   # E2E 报告
open server/coverage/index.html                        # 覆盖率报告
```