避免过度 mock 的核心是聚焦行为而非实现细节,只模拟外部不可控依赖(如网络、数据库),不 mock 内部函数或工具方法;优先用真实实例,谨慎链式 mock,用输出断言替代调用验证,并定期审查 mock 必要性。

避免 JS 中过度 Mock 的核心是让测试聚焦行为而非实现细节,只模拟真正不可控的依赖,保留尽可能多的真实交互。
只 mock 外部边界,不 mock 内部协作
第三方服务、网络请求、数据库、定时器、全局对象(如 Date、Math)属于合理 mock 范围。但不要 mock 同一模块内其他函数、类方法或工具函数——它们本就是被测系统的一部分。比如测试一个订单创建流程,可以 mock axios,但不应 mock 本项目里的 calculateDiscount() 或 formatOrderData()。
优先用真实实例,再考虑 mock
- 能直接 new 实例调用的类,就别 mock 构造函数
- 工具函数若无副作用(如纯计算),直接调用比 mock 更可靠、更易读
- 对有副作用但可控的依赖(如内存缓存、本地存储),可用轻量替代(如 new Map() 替代 localStorage)
警惕链式调用中的“中间 mock”
像 userService.find().then(user => user.profile.getAvatar()) 这类调用,不要逐层 mock find()、then()、getAvatar()。这会让测试绑定具体实现路径。正确做法是:mock userService.find() 返回一个带真实 profile 方法的对象,或直接返回预设的完整 user 数据。
基于三引擎设计,从微信文章、新闻和博客网页提取干净内容,支持标题作者日期元数据,多格式和批量处理。
用行为断言代替调用验证
少用 verify(mockService.doX()).times(1) 去检查内部方法是否被调用,多用 expect(result).toBe(...) 或 expect(output).toContain(...) 验证最终输出是否符合预期。测试的目标是“它做了什么”,不是“它怎么做的”。重构时只要行为不变,测试就不该失败。
定期清理和审查 mock 使用点
在代码评审或重构阶段,把每个 jest.mock() 或 mockImplementation() 当作可疑信号来审视:
- 这个模块真的无法在测试中正常工作吗?
- mock 是为了隔离副作用,还是为了绕过难写的逻辑?
- 去掉这个 mock,测试会失败吗?如果不会,说明它可能多余










