测试用例生成标准化模版(分包交付核心)

发布于 2026/8/4作者:TokenLens发私信来源:self
Token 建议输入 ≤15000 · 输出预留 12000claude-3.5-sonnetclaude-3.7-sonnetgpt-4o

从需求/接口契约生成结构化测试用例,覆盖功能/集成/契约/性能/安全,输出可执行测试脚本、测试数据、覆盖率门槛

提示词

你是测试架构师。任务:为分包项目生成全层级测试用例体系,作为交付验收的质量标尺。

约束:

  1. 测试金字塔:单元(70%) > 集成(20%) > E2E(10%)
  2. 来源追溯:每用例关联需求ID/契约端点/风险点
  3. 分类维度:功能、边界、异常、性能、安全、兼容性、数据迁移
  4. BDD 格式:Given/When/Then,业务可读
  5. 数据驱动:参数化测试数据、边界值、等价类划分
  6. 可执行:输出 Vitest/Playwright/Pytest 可直接跑通的代码
  7. 覆盖率门槛:语句/分支/函数/行 >= 80%
  8. CI 集成:矩阵测试、并行、失败重试、报告发布
  9. 输出:测试用例文档 + 可执行代码 + 测试数据工厂 + CI 配置

输出格式:

测试用例规范 v1.0:
追溯矩阵:
| 需求ID | 契约端点 | 测试用例ID | 类型 | 优先级 |
单元测试用例:
集成测试用例:
E2E 测试用例:
性能/安全测试用例:
// tests/unit/xxx.test.ts
// tests/integration/xxx.test.ts
// tests/e2e/xxx.spec.ts
.github/workflows/test.yml:

少样本示例

展示追溯矩阵、单元/集成/E2E 代码、性能/安全用例、CI 矩阵

输入

接口契约:POST /api/v1/auth/login(见 api-contract-design 模版)。需求:支持邮箱/手机号登录、记住我、设备指纹、失败锁定、刷新令牌。

输出

测试用例规范 v1.0 - 用户登录模块:
追溯矩阵:

需求ID契约端点测试用例ID类型优先级
REQ-001POST /auth/loginTC-LOGIN-001功能P0
REQ-001POST /auth/loginTC-LOGIN-002边界P0
REQ-002POST /auth/loginTC-LOGIN-003异常P0
REQ-003POST /auth/refreshTC-LOGIN-004功能P0
REQ-004POST /auth/loginTC-LOGIN-005安全P1

单元测试用例 (Vitest):
TC-LOGIN-001: 邮箱密码登录成功:

  • Given: 有效用户存在、密码正确、设备指纹有效
  • When: 调用 loginService.login({ email, password, deviceFingerprint })
  • Then: 返回 AuthResponse、accessToken 有效、refreshToken 有效、用户信息完整

TC-LOGIN-002: 手机号登录成功:

  • Given: 用户绑定手机号、密码正确
  • When: 调用 loginService.login({ phone, password, deviceFingerprint })
  • Then: 同邮箱登录

TC-LOGIN-003: 密码错误触发失败计数:

  • Given: 用户存在、密码错误
  • When: 连续调用 5 次登录
  • Then: 前 4 次返回 401、第 5 次返回 429(锁定)、Redis 记录失败次数

TC-LOGIN-004: 刷新令牌轮换:

  • Given: 有效 refreshToken
  • When: 调用 refreshToken()
  • Then: 返回新 accessToken+refreshToken、旧 refreshToken 失效、黑名单记录

TC-LOGIN-005: 设备指纹风控:

  • Given: 同一设备指纹 1 分钟内 20 次失败
  • When: 第 21 次请求
  • Then: 返回 429、设备指纹加入临时黑名单
// tests/unit/auth/login.service.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { LoginService } from '@/services/auth/login.service';
import { UserRepository } from '@/repositories/user.repository';
import { TokenService } from '@/services/auth/token.service';
import { RateLimiter } from '@/services/security/rate-limiter';

const mockUserRepo = vi.mocked(new UserRepository());
const mockTokenSvc = vi.mocked(new TokenService());
const mockRateLimiter = vi.mocked(new RateLimiter());

const loginSvc = new LoginService(mockUserRepo, mockTokenSvc, mockRateLimiter);

describe('LoginService', () => {
  beforeEach(() => vi.clearAllMocks());

  it('TC-LOGIN-001: email password login success', async () => {
    const user = { id: '1', email: 'test@example.com', passwordHash: 'hashed', roles: ['user'] };
    mockUserRepo.findByEmail.mockResolvedValue(user);
    mockUserRepo.verifyPassword.mockResolvedValue(true);
    mockTokenSvc.generatePair.mockResolvedValue({ accessToken: 'at', refreshToken: 'rt', expiresIn: 900 });
    mockRateLimiter.check.mockResolvedValue({ allowed: true });

    const result = await loginSvc.login({ email: 'test@example.com', password: 'pass', deviceFingerprint: 'fp1' });

    expect(result).toMatchObject({ accessToken: 'at', refreshToken: 'rt', expiresIn: 900, tokenType: 'Bearer' });
    expect(result.user.email).toBe('test@example.com');
  });

  it('TC-LOGIN-003: password error triggers lockout', async () => {
    mockUserRepo.findByEmail.mockResolvedValue({ id: '1', passwordHash: 'h' });
    mockUserRepo.verifyPassword.mockResolvedValue(false);
    mockRateLimiter.check.mockResolvedValue({ allowed: true });
    mockRateLimiter.increment.mockResolvedValue(undefined);

    for (let i = 0; i < 4; i++) {
      await expect(loginSvc.login({ email: 'a@b.com', password: 'wrong', deviceFingerprint: 'fp' }))
        .rejects.toThrow('Invalid credentials');
    }
    mockRateLimiter.check.mockResolvedValueOnce({ allowed: false, retryAfter: 300 });
    await expect(loginSvc.login({ email: 'a@b.com', password: 'wrong', deviceFingerprint: 'fp' }))
      .rejects.toThrow('Too many attempts');
  });
});
// tests/integration/auth/login.integration.test.ts
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import request from 'supertest';
import { app } from '@/app';
import { setupTestDb, teardownTestDb } from '../utils/db';

describe('POST /api/v1/auth/login (Integration)', () => {
  beforeAll(async () => { await setupTestDb(); });
  afterAll(async () => { await teardownTestDb(); });

  it('TC-LOGIN-001: full stack login', async () => {
    const res = await request(app)
      .post('/api/v1/auth/login')
      .send({ email: 'test@example.com', password: 'Password123', deviceFingerprint: 'fp-test' });
    expect(res.status).toBe(200);
    expect(res.body).toHaveProperty('accessToken');
    expect(res.body).toHaveProperty('refreshToken');
    expect(res.body.user.email).toBe('test@example.com');
  });
});
// tests/e2e/auth/login.spec.ts (Playwright)
import { test, expect } from '@playwright/test';

test.describe('Login Flow E2E', () => {
  test('TC-LOGIN-001: user logs in via UI', async ({ page }) => {
    await page.goto('/login');
    await page.fill('[data-testid=email]', 'test@example.com');
    await page.fill('[data-testid=password]', 'Password123');
    await page.click('[data-testid=submit]');
    await expect(page).toHaveURL('/dashboard');
    await expect(page.locator('[data-testid=user-name]')).toContainText('Test User');
  });
});

性能测试用例:

用例ID场景并发目标 RT(P99)通过标准
PERF-LOGIN-001正常登录100 VU< 500ms0% 错误率
PERF-LOGIN-002并发刷新令牌500 VU< 300ms0% 错误率

安全测试用例:

用例ID攻击向量预期结果
SEC-LOGIN-001SQL 注入 email 字段400 错误、无数据泄露
SEC-LOGIN-002暴力破解5 次失败后锁定 5 分钟
SEC-LOGIN-003令牌重放refreshToken 单次使用、重放拒绝

CI 配置片段:

.github/workflows/test.yml:
jobs:
  unit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run test:unit -- --coverage
  integration:
    needs: unit
    runs-on: ubuntu-latest
    services:
      postgres: ...
      redis: ...
    steps:
      - run: npm run test:integration
  e2e:
    needs: integration
    runs-on: ubuntu-latest
    steps:
      - uses: microsoft/playwright-github-action@v1
      - run: npm run test:e2e
改写到我的

评分

暂无评分

登录后可为这条 Prompt 打分

评价与讨论

直接在本页发言

加载讨论…

登录后即可在本页参与讨论

分包交付编程与工程deliverytest-casetest-generationbddacceptance