面试追问地图

主问题必讲关键点下一层追问
测试分层范围、速度、真实性测试金字塔比例如何确定
单元测试AAA、独立、可重复私有方法是否测试、静态依赖
Mock隔离依赖、验证行为过度 Mock、Fake 的价值
Spring 测试切片测试、Context 成本Context 缓存、事务回滚
Testcontainers真实依赖、环境一致启动速度、数据隔离
覆盖率执行覆盖而非质量证明分支覆盖、变异测试
并发测试同步起点、不变量、重复运行不稳定测试如何治理
契约测试消费者/提供者约定与集成测试、E2E 的区别
Code Review风险、边界、可运维性如何控制评审规模和效率
代码质量圈复杂度、技术债、可测性重构节奏、遗留系统治理

测试题应结合一个真实缺陷说明“这个测试为什么能在上线前发现问题”。


一、测试分层

单元测试、集成测试、端到端测试的区别?

难度 🟡

类型范围特点
单元测试单个类或方法快、隔离、定位准确
集成测试多组件、数据库、中间件验证真实协作,执行较慢
端到端测试完整业务链路最接近用户,但成本高且脆弱

测试金字塔强调底层测试数量多、上层测试数量少,但比例应结合系统类型调整。

什么样的代码容易测试?

  • 依赖通过构造器注入。
  • 业务逻辑与 IO、副作用分离。
  • 方法职责单一。
  • 时间、随机数、外部服务可替换。
  • 避免全局状态和静态依赖。

难测试通常是设计耦合问题,不应全部依靠高级 Mock 技巧绕过。


二、JUnit 与断言

一个好的单元测试包含什么?

使用 Arrange-Act-Assert:

准备输入和依赖

执行被测行为

验证输出、状态或交互

测试名应描述场景和预期结果,例如:

shouldRejectOrderWhenStockIsInsufficient

参数化测试适合什么场景?

适合用多组输入验证同一规则:

  • 边界值。
  • 等价类。
  • 不同枚举或状态。
  • 格式解析。

参数化测试不能代替复杂场景的独立语义测试。

如何测试异常?

不仅验证异常类型,还应验证:

  • 错误码或关键消息。
  • 依赖是否未被调用。
  • 状态是否保持不变或正确回滚。

三、Mock

Mock、Stub、Fake 有什么区别?

  • Stub:返回预设数据。
  • Mock:除了返回数据,还验证交互。
  • Fake:可工作的简化实现,如内存仓库。

什么时候不应该 Mock?

  • 纯值对象和简单数据结构。
  • 被测类内部实现细节。
  • 所有对象都 Mock 导致测试只验证调用顺序。
  • 可以低成本使用真实组件的场景。

过度 Mock 会让重构频繁破坏测试,却无法发现真实集成问题。

如何验证外部调用?

只验证有业务意义的交互:

  • 是否发送了一次支付请求。
  • 是否在失败后没有发消息。
  • 是否携带正确幂等键。

不要对无关方法调用顺序做过度约束。


四、Spring 测试

@SpringBootTest 有什么特点?

它会启动完整或接近完整的 Spring Context,适合集成测试,但速度较慢。

应按需选择:

  • 纯业务类:普通 JUnit。
  • MVC 切片:@WebMvcTest
  • JPA 切片:@DataJpaTest
  • 完整集成:@SpringBootTest

如何测试 Controller?

重点验证:

  • 参数绑定和校验。
  • HTTP 状态码。
  • 响应结构和错误码。
  • 鉴权和异常处理。

业务分支应主要在 Service 单元测试中覆盖,避免 Controller 测试过重。

如何测试数据库和中间件?

优先使用:

  • Testcontainers 启动真实数据库、Redis、Kafka 等。
  • 独立测试 Schema 和数据。
  • 每个测试可重复执行,避免依赖执行顺序。

H2 等内存数据库与 MySQL 方言、锁和执行计划可能不同,不能替代关键数据库集成测试。


五、测试策略

测试覆盖率越高越好吗?

覆盖率只能说明代码被执行过,不能证明断言有效。

重点关注:

  • 核心业务规则。
  • 边界和异常路径。
  • 历史故障回归。
  • 高风险变更。

覆盖率适合作为发现明显缺口的指标,不适合作为唯一质量目标。

如何测试并发代码?

  • 控制线程启动时机,避免依赖 sleep
  • 使用 CountDownLatch、Barrier 等同步工具。
  • 重复运行增加暴露概率。
  • 验证最终状态和不变量。
  • 必要时使用专门并发测试工具。

并发测试通过不代表绝对正确,还需依赖设计证明、代码审查和线上指标。

如何测试时间相关逻辑?

注入 Clock,不要在业务逻辑中直接散落调用系统时间。

这样可以稳定测试过期、跨天、时区和夏令时场景。

什么是契约测试?

契约测试验证服务提供方和消费方对接口结构、字段和行为的约定,适合微服务独立发布。

它不能替代端到端测试,但能更早发现接口不兼容。


六、代码质量

Code Review 重点看什么?

  • 正确性和边界条件。
  • 并发、事务和一致性。
  • 安全和敏感数据。
  • 可读性和职责边界。
  • 测试是否覆盖风险。
  • 监控、日志和回滚能力。

格式问题应尽量交给自动化工具。

什么是圈复杂度?

圈复杂度反映代码中独立执行路径数量。复杂度过高通常意味着:

  • 分支过多。
  • 方法承担多个职责。
  • 测试组合爆炸。

治理方式包括提取策略、拆分方法和用状态机显式表达流程。

如何治理技术债?

  • 记录影响和风险,不只记录“代码不好看”。
  • 优先处理频繁变更、故障高发和阻碍交付的区域。
  • 将治理拆入正常迭代。
  • 用故障率、交付时间、复杂度等指标验证收益。

参考资料