功能测试流程与自动化脚本
8.3 Mock概念
Tip
当测试涉及到“扣钱”、“发短信”、“删库”这些危险操作时,我们不能真做。我们需要一个替身。在编程里,这个技术叫 Mock (模拟)。
1. 为什么要学这个?
想象你在拍电影
你要拍一场“跳楼”的戏。
- 不用 Mock:让男主角真的从 20 楼跳下去。后果:主角挂了,电影没法拍了。
- 使用 Mock:
- 铺一个气垫(模拟环境)。
- 找一个替身演员(Mock 对象)。
- 拍完看起来像真的一样,但没人受伤。
代码里的场景
你要测试“支付成功后发邮件”的功能。
- 不用 Mock:每次跑测试,真的去调 Stripe 接口扣你 $10,真的给用户发一封骚扰邮件。
- 使用 Mock:
- 我们要劫持发邮件的函数。
- 换成一个假函数。
- 这个假函数不真发邮件,只是拿个小本本记下来:“User A 在 10:00 收到了一封邮件”。
- 测试程序检查小本本,如果记录了,就算测试通过。
2. 核心概念:替身的自我修养
在 Vitest 里,我们主要用 vi.fn() 和 vi.spyOn() 来制造替身。
1. 假扮者 (Mock Function)
- 导演说:“不管谁问你,你都只回答 'Hello'”。
- 代码:
const fakeSayHi = vi.fn().mockReturnValue('Hello'); console.log(fakeSayHi()); // 输出: Hello - 用处:不论外面发生什么,我都返回一个固定的假数据,为了让测试能跑下去。
2. 记录员 (Spy)
- 导演说:“你不用演,你就站在真正的发邮件函数旁边,帮我数着它被调用了几次”。
- 代码:
const spy = vi.spyOn(console, 'log'); console.log('Test'); expect(spy).toHaveBeenCalledTimes(1); // 断言:真的被调用了一次
3. 实战演示:Mock 掉邮件服务
假设我们有一个 payment.ts 文件,里面真的引入了发邮件的库:
// payment.ts
import { sendRealEmail } from './email-service'; // 这是一个发真邮件的库
export function pay(user, amount) {
// ... 扣款逻辑 ...
sendRealEmail(user.email, "支付成功");
}
如果我们直接测 pay(),邮件就发出去了。
我们来看测试文件 payment.test.ts 怎么写:
import { expect, test, vi } from 'vitest';
import { pay } from './payment';
import { sendRealEmail } from './email-service';
// 🛑 核心一步:告诉 Vitest,把这个文件里导出的函数全都换成假的!
vi.mock('./email-service');
test('支付成功应该触发发邮件', () => {
const user = { email: 'test@example.com' };
// 运行业务逻辑
pay(user, 100);
// ✅ 验证:因为被 mock 了,所以没真发。
// 但我们可以检查假函数是不是被“调戏”了。
expect(sendRealEmail).toHaveBeenCalledTimes(1);
expect(sendRealEmail).toHaveBeenCalledWith('test@example.com', "支付成功");
});
4. 真实案例
Story
HBO Max 的“实习生”邮件 (2021)
2021 年 6 月,成千上万的 HBO Max 订阅用户收到了一封奇怪的邮件,标题是:"Integration Test Email #1" (集成测试邮件 1 号)。 这让很多用户以为账号被黑了,甚至上了推特热搜。 真相: 一位实习生(也可能是正式员工)在生产环境跑了一个测试脚本。 这个脚本本该 Mock 掉邮件服务,或者连接到一个发不到公网的虚拟邮件服务器。 但他忘了 Mock。而且脚本直接连了真实的用户数据库。 结果:脚本像机关枪一样,毫无阻拦地向真实用户列表里的每个人发送了测试邮件。
Vibe 心法:Mock 是测试环境的“安全阀”。凡是涉及给用户发消息、扣用户的钱、删除用户的数据这些操作,必须在测试代码里安装替身。永远不要信任你的测试脚本能直接连接真实世界。
5. 本章小结
- Mock 就是替身:为了安全和省钱,用假函数代替真函数。
- vi.mock:Vitest 提供的魔法命令,可以劫持模块。
- 安全第一:只要是副作用(发邮件、写数据库、扣款),测试时必须 Mock。