Skip to content
Vitest 1
Main Navigation 指南API配置高级
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

指南

为什么选择 Vitest

快速开始

特性

工作区

命令行界面

测试筛选

报告器

代码覆盖率

快照(Snapshot)

模拟(Mocking)

类型测试

Vitest UI

浏览器模式

源码内测试

测试上下文

测试环境

扩展匹配器

IDE 集成

调试

与其他测试运行器的比较

迁移指南

常见错误

提升性能

API

测试 API 索引

模拟函数

Vi

expect

expectTypeOf

assert(断言)

assertType

配置

管理 Vitest 配置文件

配置 Vitest

页面导航

模拟函数 ​

你可以使用 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) 2024 Mithril Contributors

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

基于 MIT 许可证 发布。

版权所有 (c) 2024 Mithril Contributors