题目重点:围绕题目明确的“怎么写 unit test、有什么好处”追问,用具体输入输出契约说明正常、边界、异常和回归测试。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 示例函数 allocate(alias, url) 返回短码或明确错误;依赖唯一索引、时钟与随机源都可注入。
- 单元测试验证局部逻辑;数据库唯一性、HTTP 重定向和队列交付另设集成测试,不把 mock 的成功当作端到端正确。
解题路线
- 先写可观察的契约:合法 alias 创建记录;重复 alias 冲突;无效 URL 拒绝;存储暂不可用时按既定错误返回。每个断言检查行为或持久化效果,而非私有方法调用次数。
- 正常例验证返回码和存储状态;边界例覆盖最短/最长 alias、Unicode 或保留字符;异常例覆盖冲突、超时与重试;回归例固定已经发生过的缺陷。
- 使用固定时钟和可重复随机源减少偶发失败,隔离每个测试的数据;必要时用参数化覆盖等价类,但不要为微小实现细节堆测试。
- 测试收益要具体:快速指出破坏的业务契约、支持重构、保存边界知识;同时承认单测不能证明系统集成或并发安全。
手动走一遍
allocate('abc', validUrl) 成功后查询到同一目标;再 allocate('abc', otherUrl) 应冲突而不覆盖旧值。模拟一次数据库超时,确认函数返回可重试错误;测试恢复后再提交,确保不会产生两个相同 alias。
规模与取舍
测试数量取决于独立业务分支和失败模式;示例每例 O(1) 次接口调用。实践中更应衡量执行时长、误报率与缺陷覆盖,而不是追求一个固定测试行数。
易错点与追问
容易失分的边界
- 只断言函数被调用,没有检查可见结果。
- 大量 mock 掉核心逻辑,使测试通过却不保护行为。
- 依赖真实当前时间或网络服务导致不稳定。
- 把单测覆盖率百分比当作正确性证明。
继续深挖
- 并发创建相同 alias 的唯一性应放在哪层测试?
- 遗留代码难以注入依赖时如何逐步增加测试缝隙?
- 哪些场景适合性质测试、随机对照或故障注入?
