Skip to content
Vitest 1
Main Navigation 指南API配置高级
3.2.0
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 方法创建一个模拟函数来追踪其执行情况。如果你想追踪已创建对象上的方法,可以使用 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 参考描述了可用于操作模拟行为的属性和方法。

getMockImplementation ​

  • 类型: (...args: any) => any

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

如果模拟函数是通过 vi.fn 创建的,它会将传入的方法视为模拟实现。

如果模拟函数是通过 vi.spyOn 创建的,它将返回 undefined,除非提供了自定义实现。

getMockName ​

  • 类型: () => string

返回使用 .mockName(name) 方法赋予模拟函数的名称。如果断言失败,这有助于查看模拟函数的名称,方便调试。

mockClear ​

  • 类型: () => MockInstance

清除每次调用模拟函数时记录的所有信息。调用该方法后,.mock 上的所有属性将返回空状态。此方法不会重置模拟函数的实现。如果你需要在不同的断言之间清理模拟函数,它会很有用。

如果你希望在每次测试之前自动调用此方法,你可以在配置中启用 clearMocks 设置。

mockName ​

  • 类型: (name: string) => MockInstance

设置模拟函数的内部名称。如果断言失败,可以使用此名称来帮助识别模拟函数。

mockImplementation ​

  • 类型: (fn: Function) => MockInstance

接受一个函数,该函数将用作模拟函数的实现。

ts
import { vi } from 'vitest';
// ---cut---
const mockFn = vi.fn().mockImplementation(apples => apples + 1);
// or: 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 ​

  • 类型: (fn: Function) => MockInstance

接受一个函数,该函数将在下一次调用时作为模拟函数的实现。支持链式调用,以便多次函数调用产生不同的结果。

ts
import { vi } from 'vitest';
// ---cut---
const myMockFn = vi
  .fn()
  .mockImplementationOnce(() => true)
  .mockImplementationOnce(() => false);

myMockFn(); // true
myMockFn(); // false

当模拟函数的临时实现全部使用完毕后,它将调用使用 vi.fn(() => defaultValue) 或 .mockImplementation(() => defaultValue) 设置的默认实现(如果已调用):

ts
import { vi } from 'vitest';
// ---cut---
const myMockFn = vi
  .fn(() => 'default')
  .mockImplementationOnce(() => 'first call')
  .mockImplementationOnce(() => 'second call');

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

withImplementation ​

  • 类型: (fn: Function, callback: () => void) => MockInstance
  • 类型: (fn: Function, callback: () => Promise<unknown>) => Promise<MockInstance>

在执行回调函数期间,临时覆盖原始的模拟函数实现。

js
import { vi } from 'vitest';
// ---cut---
const myMockFn = vi.fn(() => 'original');

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

myMockFn(); // 'original'

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

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

  // We await this call since the callback is async
  await myMockFn.withImplementation(
    () => 'temp',
    async () => {
      myMockFn(); // 'temp'
    }
  );

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

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

mockRejectedValue ​

  • 类型: (value: any) => MockInstance

接受一个值,该值将在异步函数调用时被 Promise 拒绝(reject)。

ts
import { vi } from 'vitest';
// ---cut---
const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'));

await asyncMock(); // throws "Async error"

mockRejectedValueOnce ​

  • 类型: (value: any) => MockInstance

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

ts
import { vi } from 'vitest';
// ---cut---
const asyncMock = vi
  .fn()
  .mockResolvedValueOnce('first call')
  .mockRejectedValueOnce(new Error('Async error'));

await asyncMock(); // first call
await asyncMock(); // throws "Async error"

mockReset ​

  • 类型: () => MockInstance

执行与 mockClear 相同的操作,并将内部实现设置为空函数(调用后返回 undefined)。这也会重置所有 "once" 实现。当你想要将模拟函数完全重置为默认状态时,这很有用。

如果你希望在每次测试之前自动调用此方法,你可以在配置中启用 mockReset 设置。

mockRestore ​

  • 类型: () => MockInstance

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

请注意,从 vi.fn() 恢复模拟函数会将实现设置为返回 undefined 的空函数。恢复 vi.fn(impl) 会将实现恢复为 impl。

如果你希望在每次测试之前自动调用此方法,你可以在配置中启用 restoreMocks 设置。

mockResolvedValue ​

  • 类型: (value: any) => MockInstance

接受一个值,该值将在调用异步函数时被 Promise 解析(resolve)。

ts
import { vi } from 'vitest';
// ---cut---
const asyncMock = vi.fn().mockResolvedValue(42);

await asyncMock(); // 42

mockResolvedValueOnce ​

  • 类型: (value: any) => MockInstance

接受一个值,该值将在下一次函数调用期间被 Promise 解析(resolve)。如果链式调用,则每次连续调用都将解析指定的值。

ts
import { vi } from 'vitest';
// ---cut---
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 ​

  • 类型: () => MockInstance

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

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

mockReturnValue ​

  • 类型: (value: any) => MockInstance

接受一个值,该值将在每次调用模拟函数时返回。

ts
import { vi } from 'vitest';
// ---cut---
const mock = vi.fn();
mock.mockReturnValue(42);
mock(); // 42
mock.mockReturnValue(43);
mock(); // 43

mockReturnValueOnce ​

  • 类型: (value: any) => MockInstance

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

当所有 mockReturnValueOnce 值都被使用后,如果存在先前定义的实现,模拟函数将回退到该实现。

ts
import { vi } from 'vitest';
// ---cut---
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 ​

这是一个数组,数组中的每个元素代表一次调用时传入的参数列表。

js
const fn = vi.fn();

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

fn.mock.calls ===
  [
    ['arg1', 'arg2'], // first call
    ['arg3'], // second call
  ];

mock.lastCall ​

这包含最后一次调用的参数列表。如果未调用模拟函数,将返回 undefined。

mock.results ​

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

  • 'return' - 函数正常返回,没有抛出异常。
  • 'throw' - 函数抛出了一个异常。

value 属性包含返回值或抛出的错误。如果函数返回一个 Promise,则 value 将是已解析的值,而不是实际的 Promise 对象,除非该 Promise 从未被解析。

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

const result = fn(); // returned 'result'

try {
  fn(); // threw Error
} catch {}

fn.mock.results ===
  [
    // first result
    {
      type: 'return',
      value: 'result',
    },
    // last result
    {
      type: 'throw',
      value: Error,
    },
  ];

mock.invocationCallOrder ​

模拟函数的执行顺序。这将返回一个数字数组,其中的数字代表所有已定义的模拟函数的调用顺序。

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

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

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

mock.instances ​

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

WARNING

如果使用 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) 2021-Present Vitest Team

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

基于 MIT 许可证 发布。

版权所有 (c) 2021-Present Vitest Team