Skip to content
Vitest 2
Main Navigation 指南API配置浏览器模式高级
2.1.9
1.6.1
0.34.6

简体中文

English
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

简体中文

English
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

主题

Sidebar Navigation

测试 API 索引

模拟函数

Vi

expect

expectTypeOf

assert(断言)

assertType

页面导航

模拟函数 ​

你可以使用 vi.fn 方法创建一个模拟函数(Mock Function)来跟踪其调用。如果你想跟踪一个已创建对象的方法,可以使用 vi.spyOn 方法:

js
import { vi } from 'vitest';

const fn = vi.fn();
fn('hello world');
fn.mock.calls[0] === ['hello world'];

const market = {
  getApples: () => 100,
};

const getApplesSpy = vi.spyOn(market, 'getApples');
market.getApples();
getApplesSpy.mock.calls.length === 1;

你应该使用 expect 上的模拟断言(例如 toHaveBeenCalled)来断言模拟结果。本 API 参考文档描述了可用的属性和方法来控制模拟行为。

TIP

下面类型定义中自定义函数实现使用泛型 <T> 标注。

getMockImplementation ​

ts
function getMockImplementation(): T | undefined;

如果存在,则返回当前的模拟实现函数。

如果 mock 是使用 vi.fn 创建的,它将使用提供的实现函数作为 mock 实现。

如果 mock 是使用 vi.spyOn 创建的,除非提供了自定义实现,否则返回 undefined。

getMockName ​

ts
function getMockName(): string;

用于返回使用 .mockName(name) 方法分配给 mock 的名称。默认情况下,返回 vi.fn()。

mockClear ​

ts
function mockClear(): MockInstance<T>;

清除每次调用的所有信息。调用此方法后,.mock 上的所有属性将恢复到其初始状态。此方法不会重置实现。对于在不同断言之间清理模拟对象非常有用。

要在每次测试之前自动调用此方法,请在配置中启用 clearMocks 设置。

mockName ​

ts
function mockName(name: string): MockInstance<T>;

设置内部模拟名称。这有助于在断言失败时识别 mock。

mockImplementation ​

ts
function mockImplementation(fn: T): MockInstance<T>;

接受一个函数作为 mock 实现。TypeScript 要求参数和返回类型与原始函数一致。

ts
const mockFn = vi.fn().mockImplementation((apples: number) => apples + 1);
// 或者:vi.fn(apples => apples + 1);

const NelliesBucket = mockFn(0);
const BobsBucket = mockFn(1);

NelliesBucket === 1; // true
BobsBucket === 2; // true

mockFn.mock.calls[0][0] === 0; // true
mockFn.mock.calls[1][0] === 1; // true

mockImplementationOnce ​

ts
function mockImplementationOnce(fn: T): MockInstance<T>;

接受一个函数作为 mock 实现。TypeScript 要求参数和返回类型与原始函数一致。此方法可以链式调用,为多次函数调用提供不同的结果。

ts
const myMockFn = vi
  .fn()
  .mockImplementationOnce(() => true) // 第一次调用
  .mockImplementationOnce(() => false); // 第二次调用

myMockFn(); // 第一次调用:true
myMockFn(); // 第二次调用:false

当模拟函数没有更多一次性实现时,如果设置了默认实现(通过 vi.fn(() => defaultValue) 或 .mockImplementation(() => defaultValue)),将调用默认实现:

ts
const myMockFn = vi
  .fn(() => 'default')
  .mockImplementationOnce(() => 'first call')
  .mockImplementationOnce(() => 'second call');

// 'first call', 'second call', 'default', 'default'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());

withImplementation ​

ts
function withImplementation(fn: T, cb: () => void): MockInstance<T>;
function withImplementation(
  fn: T,
  cb: () => Promise<void>
): Promise<MockInstance<T>>;

在回调执行期间临时覆盖原始 mock 实现。

js
const myMockFn = vi.fn(() => 'original');

myMockFn.withImplementation(
  () => 'temp',
  () => {
    myMockFn(); // 'temp'
  }
);

myMockFn(); // 'original'

可以与异步回调一起使用。需要等待该方法执行完毕才能恢复使用原始实现。

ts
test('async callback', async () => {
  const myMockFn = vi.fn(() => 'original');

  // 我们等待此调用,因为回调是异步的
  await myMockFn.withImplementation(
    () => 'temp',
    async () => {
      myMockFn(); // 'temp'
    }
  );

  myMockFn(); // 'original'
});

请注意,此方法优先于 mockImplementationOnce。

mockRejectedValue ​

ts
function mockRejectedValue(value: unknown): MockInstance<T>;

接受一个错误,当调用异步函数时将会被拒绝。

ts
const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'));

await asyncMock(); // 抛出 Error<'Async error'>

mockRejectedValueOnce ​

ts
function mockRejectedValueOnce(value: unknown): MockInstance<T>;

接受一个值,该值将在下一次函数调用期间被拒绝。如果链式调用,每次连续调用都将拒绝指定的值。

ts
const asyncMock = vi
  .fn()
  .mockResolvedValueOnce('first call')
  .mockRejectedValueOnce(new Error('Async error'));

await asyncMock(); // 'first call'
await asyncMock(); // 抛出 Error<'Async error'>

mockReset ​

ts
function mockReset(): MockInstance<T>;

执行与 mockClear 相同的操作,并将内部实现设置为空函数(调用时返回 undefined)。这也重置所有 "once" 实现。对于将 mock 完全重置为其默认状态非常有用。

要在每次测试之前自动调用此方法,请在配置中启用 mockReset 设置。

mockRestore ​

ts
function mockRestore(): MockInstance<T>;

执行与 mockReset 相同的操作,并将内部实现恢复为原始函数。

请注意,恢复使用 vi.fn() 创建的 mock 将把实现设置为空函数,返回 undefined。恢复使用 vi.fn(impl) 创建的 mock 将把实现恢复为 impl。

要在每次测试之前自动调用此方法,请在配置中启用 restoreMocks 设置。

mockResolvedValue ​

ts
function mockResolvedValue(value: Awaited<ReturnType<T>>): MockInstance<T>;

接受一个值,当调用异步函数时将被解析。TypeScript 只接受与原始函数返回类型匹配的值。

ts
const asyncMock = vi.fn().mockResolvedValue(42);

await asyncMock(); // 42

mockResolvedValueOnce ​

ts
function mockResolvedValueOnce(value: Awaited<ReturnType<T>>): MockInstance<T>;

接受一个值,该值将在下一次函数调用期间被解析。TypeScript 只接受与原始函数返回类型匹配的值。如果链式调用,每次连续调用都将解析指定的值。

ts
const asyncMock = vi
  .fn()
  .mockResolvedValue('default')
  .mockResolvedValueOnce('first call')
  .mockResolvedValueOnce('second call');

await asyncMock(); // first call
await asyncMock(); // second call
await asyncMock(); // default
await asyncMock(); // default

mockReturnThis ​

ts
function mockReturnThis(): MockInstance<T>;

如果你需要从方法返回 this 上下文而不调用实际实现,请使用此方法。这是以下代码的简写:

ts
spy.mockImplementation(function () {
  return this;
});

mockReturnValue ​

ts
function mockReturnValue(value: ReturnType<T>): MockInstance<T>;

接受一个值,无论何时调用 mock 函数都将返回该值。TypeScript 只接受与原始函数返回类型匹配的值。

ts
const mock = vi.fn();
mock.mockReturnValue(42);
mock(); // 42
mock.mockReturnValue(43);
mock(); // 43

mockReturnValueOnce ​

ts
function mockReturnValueOnce(value: ReturnType<T>): MockInstance<T>;

接受一个值,无论何时调用 mock 函数都将返回该值。TypeScript 只接受与原始函数返回类型匹配的值。

当模拟函数没有更多一次性实现时,如果调用了 vi.fn(() => defaultValue) 或 .mockImplementation(() => defaultValue),它将调用默认实现:

ts
const myMockFn = vi
  .fn()
  .mockReturnValue('default')
  .mockReturnValueOnce('first call')
  .mockReturnValueOnce('second call');

// 'first call', 'second call', 'default', 'default'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());

mock.calls ​

ts
const calls: Parameters<T>[];

这是一个数组,包含每次调用的所有参数。数组中的一项是该次调用的参数数组。

js
const fn = vi.fn();

fn('arg1', 'arg2');
fn('arg3');

fn.mock.calls ===
  [
    ['arg1', 'arg2'], // 第一次调用
    ['arg3'], // 第二次调用
  ];

mock.lastCall ​

ts
const lastCall: Parameters<T> | undefined;

这包含最后一次调用的参数数组。如果 mock 未被调用,返回 undefined。

mock.results ​

ts
interface MockResultReturn<T> {
  type: 'return';
  /**
   * 函数返回的值。
   * 如果函数返回 Promise,则这将是解析后的值。
   */
  value: T;
}

interface MockResultIncomplete {
  type: 'incomplete';
  value: undefined;
}

interface MockResultThrow {
  type: 'throw';
  /**
   * 函数执行期间抛出的错误。
   */
  value: any;
}

type MockResult<T> =
  | MockResultReturn<T>
  | MockResultThrow
  | MockResultIncomplete;

const results: MockResult<ReturnType<T>>[];

这是一个数组,包含函数返回的所有结果。数组中的一项是一个包含 type 和 value 属性的对象。可用类型有:

  • 'return' - 函数正常返回而未抛出异常。
  • 'throw' - 函数抛出了异常。

value 属性包含返回值或抛出的错误。如果函数返回 Promise,即使是 Promise 被拒绝,result 的 type 也始终是 'return'。

js
const fn = vi
  .fn()
  .mockReturnValueOnce('result')
  .mockImplementationOnce(() => {
    throw new Error('thrown error');
  });

const result = fn(); // 返回 'result'

try {
  fn(); // 抛出 Error
} catch {}

fn.mock.results ===
  [
    // 第一个结果
    {
      type: 'return',
      value: 'result',
    },
    // 最后一个结果
    {
      type: 'throw',
      value: Error,
    },
  ];

mock.settledResults ​

ts
interface MockSettledResultFulfilled<T> {
  type: 'fulfilled';
  value: T;
}

interface MockSettledResultRejected {
  type: 'rejected';
  value: any;
}

export type MockSettledResult<T> =
  | MockSettledResultFulfilled<T>
  | MockSettledResultRejected;

const settledResults: MockSettledResult<Awaited<ReturnType<T>>>[];

一个数组,包含函数解析或拒绝的所有值。

如果函数从未被解析或拒绝,则此数组将为空。

js
const fn = vi.fn().mockResolvedValueOnce('result');

const result = fn();

fn.mock.settledResults === [];

await result;

fn.mock.settledResults ===
  [
    {
      type: 'fulfilled',
      value: 'result',
    },
  ];

mock.invocationCallOrder ​

ts
const invocationCallOrder: number[];

此属性返回模拟函数的执行顺序。它是一个数字数组,在所有已定义的 mock 之间共享。

js
const fn1 = vi.fn();
const fn2 = vi.fn();

fn1();
fn2();
fn1();

fn1.mock.invocationCallOrder === [1, 3];
fn2.mock.invocationCallOrder === [2];

mock.contexts ​

ts
const contexts: ThisParameterType<T>[];

此属性是一个数组,包含在每次调用模拟函数期间使用的 this 值。

js
const fn = vi.fn();
const context = {};

fn.apply(context);
fn.call(context);

fn.mock.contexts[0] === context;
fn.mock.contexts[1] === context;

mock.instances ​

ts
const instances: ReturnType<T>[];

此属性是一个数组,包含当使用 new 关键字调用模拟函数时创建的所有实例。请注意,这是函数的实际上下文 (this),而不是返回值。

WARNING

如果 mock 是使用 new MyClass() 实例化的,则 mock.instances 将是一个包含一个值的数组:

js
const MyClass = vi.fn();
const a = new MyClass();

MyClass.mock.instances[0] === a;

如果你从构造函数返回一个值,它将不会在 instances 数组中,而是在 results 中:

js
const Spy = vi.fn(() => ({ method: vi.fn() }));
const a = new Spy();

Spy.mock.instances[0] !== a;
Spy.mock.results[0] === a;
Pager
上一页测试 API 索引
下一页Vi

基于 MIT 许可证 发布。

版权所有 (c) 2024 Mithril Contributors

https://v2.vitest.dev/api/mock

基于 MIT 许可证 发布。

版权所有 (c) 2024 Mithril Contributors