Vibe Tutorial
功能测试流程与自动化脚本

8.3 Mock概念

Tip

当测试涉及到“扣钱”、“发短信”、“删库”这些危险操作时,我们不能真做。我们需要一个替身。在编程里,这个技术叫 Mock (模拟)


1. 为什么要学这个?

想象你在拍电影

你要拍一场“跳楼”的戏。

  • 不用 Mock:让男主角真的从 20 楼跳下去。后果:主角挂了,电影没法拍了。
  • 使用 Mock
    1. 铺一个气垫(模拟环境)。
    2. 找一个替身演员(Mock 对象)。
    3. 拍完看起来像真的一样,但没人受伤。

代码里的场景

你要测试“支付成功后发邮件”的功能。

  • 不用 Mock:每次跑测试,真的去调 Stripe 接口扣你 $10,真的给用户发一封骚扰邮件。
  • 使用 Mock
    1. 我们要劫持发邮件的函数。
    2. 换成一个假函数
    3. 这个假函数不真发邮件,只是拿个小本本记下来:“User A 在 10:00 收到了一封邮件”。
    4. 测试程序检查小本本,如果记录了,就算测试通过。

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. 本章小结

  1. Mock 就是替身:为了安全和省钱,用假函数代替真函数。
  2. vi.mock:Vitest 提供的魔法命令,可以劫持模块。
  3. 安全第一:只要是副作用(发邮件、写数据库、扣款),测试时必须 Mock。