SuperAPI AI 工具集

testing-implementation

测试与质量

查看项目

更新于 10-16 10:18

技能介绍

测试实现(Testing Implementation)

适用场景

  • 单元测试实现(业务逻辑、工具函数)
  • 集成测试实现(DB、Redis、HTTP)
  • 契约测试(消费者驱动 / Pact)
  • E2E 测试(少量、关键路径)
  • Mock / Stub / Fake 设计
  • 测试数据管理
  • 性能基准测试

核心原则

  1. 测试金字塔:单元(70%)+ 集成(20%)+ E2E(10%)
  2. AAA 模式:Arrange(准备)+ Act(执行)+ Assert(断言)
  3. 一个用例测一件事;多个断言但围绕一个行为
  4. 命名说明意图,如 shouldReturnError_WhenAmountIsNegative,而不是 test_001 / testCreateOrder
  5. 不测实现细节,测行为输出,不测内部调用顺序
  6. Mock 适度:Mock 外部依赖,不 Mock 自己写的代码
  7. 集成测试用真实依赖,用 Testcontainers,不用 H2 / Mock DB
  8. 测试运行快:单元 < 100ms,集成 < 5s,全套 < 5min

测试金字塔实现

单元测试数量 1000+,覆盖业务逻辑、工具函数;集成测试 50~200 个,覆盖 API 端到端、DB / Redis;E2E 测试 5~15 个,覆盖核心用户旅程,慢且贵。

AAA 模式示例(Java + JUnit 5 + AssertJ)中通过 OrderFactory 准备数据,调用 cancel() 后断言状态变为 CANCELLED 且 cancelledAt 非空;对非法状态则断言抛出 IllegalStateException 并包含提示信息。

单元测试范式

  • Java + JUnit 5 + Mockito + AssertJ:使用 @ExtendWith(MockitoExtension.class)、@Mock、@InjectMocks,配合 given/willReturn、verify 进行验证,并用 @ParameterizedTest + @ValueSource 覆盖边界值。
  • TypeScript + Jest:使用 jest.Mocked、createMock、beforeEach 构建被测服务,使用 it.each 表驱动覆盖错误码。
  • TypeScript + Vitest:使用 describe / it / expect / vi,示例验证已支付订单取消后状态为 CANCELLED。
  • Python + pytest:使用 @pytest.fixture、Mock(spec=...)、断言 assert_called_once,并用 @pytest.mark.parametrize 覆盖数量校验。
  • Go testing:使用表驱动测试(tests 切片 + t.Run),配合 mockery 生成的 mocks.NewOrderRepository(t)。

集成测试(Testcontainers)

  • Spring Boot + Testcontainers:通过 @Testcontainers、@Container 启动 PostgreSQL 16 与 Redis 7,使用 @DynamicPropertySource 注入连接信息,通过 MockMvc 调用接口并断言数据库计数。
  • NestJS + Testcontainers:通过 @testcontainers/postgresql 的 PostgreSqlContainer 启动数据库,设置 DATABASE_URL,构建 Nest 应用后使用 supertest 请求接口。
  • Python + pytest + testcontainers:使用 PostgresContainer 会话级 fixture,注入 DATABASE_URL 后用 client 请求接口并断言返回。

契约测试(Pact)

消费者驱动契约测试流程:前端(消费者)写期望契约 → Pact Broker 存契约 → 后端(服务方)跑契约测试验证能满足 → 双方都通过即联调安全。可避免接口部署后才发现契约不一致、Mock 与真实服务行为不一致的问题。消费者侧示例使用 PactV3 定义 given / uponReceiving / withRequest / willRespondWith,服务方侧使用 @Provider、@PactBroker、@State 与 PactVerificationInvocationContextProvider 验证交互。

测试替身(Test Doubles)

  • Mock:验证调用,如 verify(repo).save(any())
  • Stub:返回预设值,如 when(repo.find(1)).thenReturn(user)
  • Spy:真实对象 + 监视,如 Spy<EmailService>
  • Fake:简化实现,如 InMemoryOrderRepository
  • Dummy:占位(不被用),如 null 替代

测试数据工厂

使用 Fishery / Faker 定义工厂,如 userFactory = Factory.define<User>(...),可 build()、带覆盖字段 build({ role: 'admin' })、buildList(10)。

性能基准测试

  • Java:JMH,@Benchmark + @OutputTimeUnit
  • JS/TS:Vitest bench
  • Go:BenchmarkCreateOrder,使用 b.ResetTimer() 与 b.N 循环

测试覆盖率

参考目标:业务逻辑(Service / Domain)≥ 80%,Controller ≥ 60%,Repository ≥ 50%,总体 ≥ 70%。工具包括 Java 的 JaCoCo、JS/TS 的 Jest --coverage / Vitest --coverage、Python 的 pytest-cov、Go 的 go test -cover。注意覆盖率高不等于测试好,覆盖率只是基础线。

工作流程

  1. TDD(推荐):先写测试(红)→ 写代码让测试过(绿)→ 重构(保绿)
  2. 单元测试:测纯业务逻辑,Mock 外部依赖,快、可重复
  3. 集成测试:测端到端流程,用 Testcontainers,主路径 + 关键失败路径
  4. 契约测试:跨服务调用,消费者驱动
  5. E2E 测试:关键用户旅程(5~15 条),慢但全面
  6. 性能基准:关键热路径,监控退化

配套模板

templates/test-implementation-checklist.md — 测试金字塔 + AAA + 测试替身 + Testcontainers + 覆盖率

质量自检

  • 单元测试覆盖业务逻辑 ≥ 80%
  • 集成测试覆盖主路径
  • AAA 模式
  • 测试命名表达意图
  • 一个用例测一件事
  • 不测实现细节
  • Mock 适度(不 Mock 自己代码)
  • 集成测试用真依赖(Testcontainers)
  • 测试快(单元 < 100ms)
  • 测试独立(不依赖顺序)
  • 测试数据用工厂
  • 关键路径有 E2E
  • 跨服务有契约测试
  • 性能基准(热路径)

常见坑

  • 测实现细节——重构时大量测试挂
  • 过度 Mock——Mock 自己代码 = 测假
  • 用 H2 / SQLite 替代 PG——行为差异
  • 测试数据手写——下次跑环境变了
  • 测试顺序依赖——并行就崩
  • 覆盖率追求 100%——getter/setter 也测
  • 断言不精确——.toBeTruthy() 而非具体值
  • 不写失败路径——只测 happy path
  • 测试不快——5 分钟跑完就没人跑
  • 测试不独立——共享状态污染
  • Mock 与真实行为不一致——线上 Bug
  • 没有契约测试——前后端联调返工
  • 重构没有测试网——不敢改
  • 测试代码不维护——"测试代码不重要"

与其他 skill 的协作

上游:domain-modeling → 单元测试领域模型;api-implementation → 集成测试 Controller;data-access → 仓储测试。 下游:qa-engineer 工作流 → QA 用例 + 测试策略;automation-qa 工作流 → CI 集成;observability → 测试时的日志。

相关参考

  • 项目根 references/backend-tech-stack-guide.md — 测试工具
  • qa-engineer 工作流测试方法论