阶段7: 测试与质量
目标: 核心业务逻辑有测试覆盖,CI 自动跑测试,测试失败阻止合并。
| 模块 | 内容 |
|---|---|
| 阶段 0 | 测试基础(单元/集成/E2E、测试金字塔、TDD) |
步骤 1:单元测试
Section titled “步骤 1:单元测试”用表驱动测试覆盖纯业务逻辑。
请帮我为酒店预订系统编写 Go 单元测试,使用表驱动测试风格:
1. 价格计算测试(services/pricing_test.go): - 普通日期:标准间 ¥300/晚 × 3 晚 = ¥900 - 周末加价:周五周六 ×1.2 倍 - 节假日加价:国庆 ×1.5 倍 - 长住折扣:>=7 晚打 9 折 - 边界值:0 晚、负数晚、超过 365 晚
2. 日期验证测试(services/booking_test.go): - CheckIn 在今天之前 → 拒绝 - CheckOut <= CheckIn → 拒绝 - 入住时间超过 1 年后 → 拒绝 - 正常日期范围 → 通过
3. 预订状态机测试(models/booking_test.go): - pending → confirmed(支付成功)→ 合法 - pending → cancelled(用户取消)→ 合法 - confirmed → checked_in → checked_out → 合法 - checked_out → confirmed → 非法 - cancelled → confirmed → 非法
4. JWT 工具测试(utils/jwt_test.go): - 正常生成和解析 - 过期 token → 返回错误 - 篡改 token → 返回错误 - 空 token → 返回错误
要求:- 每个测试函数用 t.Run() 子测试- 用 testify/assert 断言- 测试文件放在同包下- 运行命令:go test ./... -v -count=1
给出完整的测试代码。步骤 2:集成测试
Section titled “步骤 2:集成测试”测试 API 端到端行为,使用测试数据库。
请帮我为酒店预订系统编写 Go 集成测试:
测试环境搭建:- 使用独立的测试数据库(test_hotel_booking)- 每个测试前清空相关表,插入测试数据- 写一个 TestMain 函数统一初始化数据库连接- 使用 httptest 发起 HTTP 请求
测试用例:
1. 搜索 API 测试(handlers/search_test.go): - 按城市搜索 → 返回该城市的房间 - 按日期搜索 → 排除已被预订的房间 - 按价格区间搜索 → 只返回范围内的房间 - 无结果 → 返回空数组而非 null - 无参数 → 返回 400
2. 预订 API 测试(handlers/booking_test.go): - 正常预订 → 201 + 返回预订详情 - 房间已被预订(日期冲突)→ 409 - 房间不存在 → 404 - 未登录 → 401 - 参数不完整 → 400
3. 取消预订 API 测试: - 本人取消 pending 状态 → 200 - 取消他人预订 → 403 - 取消已入住预订 → 400 - 预订不存在 → 404
4. 并发预订测试: - 10 个协程同时预订同一房间同一日期 - 只有 1 个成功,其余返回 409 - 用 sync.WaitGroup 并行发请求
给出完整的测试代码,包括 TestMain 和辅助函数。步骤 3:E2E 测试
Section titled “步骤 3:E2E 测试”使用 Playwright 测试用户完整流程。
请帮我为酒店预订系统编写 Playwright E2E 测试:
环境准备:- 安装 @playwright/test- 配置 playwright.config.ts(baseURL: http://localhost:5173)- 测试前确保后端和前端都在运行
测试流程(tests/booking-flow.spec.ts):
1. 搜索房间: - 打开首页 - 输入城市"杭州",选择入住/离店日期 - 点击搜索 - 断言:显示搜索结果列表,至少有 1 个房间
2. 预订房间: - 点击第一个搜索结果的"预订"按钮 - 如未登录,先完成登录(用测试账号) - 填写入住人信息 - 确认预订 - 断言:显示预订成功页,有预订编号
3. 查看预订: - 进入"我的预订"页面 - 断言:列表中有刚才的预订,状态为 pending
4. 取消预订: - 点击"取消预订"按钮 - 确认取消 - 断言:状态变为 cancelled
辅助:- 写一个 login 辅助函数,复用登录逻辑- 测试数据用 API 直接创建(不依赖 UI seed)- 截图保存到 test-results/
给出完整的测试代码和配置文件。步骤 4:CI 集成
Section titled “步骤 4:CI 集成”配置 GitHub Actions,push 自动跑测试。
请帮我为酒店预订系统配置 GitHub Actions CI:
文件:.github/workflows/ci.yml
要求:1. 触发条件:push 到 main 和 PR 到 main2. Go 后端测试 Job: - 启动 PostgreSQL service container - 启动 Redis service container - 安装 Go 1.22 - 运行 go vet ./... - 运行 go test ./... -v -race -coverprofile=coverage.out - 上传覆盖率报告3. 前端测试 Job(并行): - 安装 Node.js 20 - npm ci - npm run lint - npm run build(确保构建不报错)4. 规则: - 任一 Job 失败则整个 CI 失败 - PR 必须 CI 通过才能合并(branch protection rule) - 缓存 Go modules 和 npm 依赖加速
给出完整的 ci.yml 文件和 branch protection 配置说明。- 价格计算、日期验证、状态机有表驱动单元测试
- 搜索/预订/取消 API 有集成测试,覆盖正常和异常路径
- 并发预订测试确认只有一个成功
- Playwright E2E 测试覆盖搜索→预订→取消流程
- GitHub Actions CI 配置完成,push 自动跑测试
- PR 必须 CI 通过才能合并
-
集成测试污染开发数据库: 测试必须使用独立的测试数据库(如
test_hotel_booking),并在 TestMain 中通过环境变量切换。千万不要在生产或开发数据库上跑测试——清表操作会删掉所有数据。 -
并发测试不稳定: 并发预订测试偶尔全部失败或多个成功,原因是数据库没有正确的唯一约束或行锁。确认
bookings表有(room_id, date)的唯一索引,且预订逻辑使用了SELECT ... FOR UPDATE。 -
CI 中 PostgreSQL 连接失败: GitHub Actions 的 service container 需要时间启动。在测试步骤前加
pg_isready等待,或在连接代码中加重试逻辑。环境变量用${{ secrets.DATABASE_URL }}或直接用 service container 的连接信息。 -
E2E 测试在 CI 中跑不起来: Playwright 需要浏览器二进制文件,CI 中用
npx playwright install --with-deps安装。另外 E2E 依赖前后端都运行,CI 中需要在 background 启动服务后再跑测试,或者先跳过 E2E 只在本地跑。