Skip to content
Vitest 3
Main Navigation 指南 & API配置瀏覽器模式進階 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

簡介

為何選擇 Vitest

快速入門

功能特色

配置參考

API

測試 API 參考

模擬函式

Vi

expect

expectTypeOf

assert

assertType

指南

命令列介面

測試篩選

測試專案

報告器

程式碼覆蓋率

快照

模擬(Mocking)

平行化

型別測試

Vitest UI

內聯測試

測試上下文

測試註解

測試環境

擴展匹配器

IDE 整合

偵錯

常見錯誤

遷移指南

遷移到 Vitest 3.0

從 Jest 遷移

效能

測試效能分析

提升效能

瀏覽器模式

進階 API

與其他測試執行器的比較

本頁導覽

模擬函式 ​

您可以使用 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 參考描述了可用於操作模擬行為的屬性和方法。

TIP

以下類型中的自訂函式實作以泛型 <T> 標記。

getMockImplementation ​

ts
function getMockImplementation(): T | undefined;

若存在,則傳回目前的模擬實作。

如果模擬是使用 vi.fn 建立的,它會使用提供的方法作為模擬實作。

如果模擬是使用 vi.spyOn 建立的,除非提供了自訂實作,否則它會傳回 undefined。

getMockName ​

ts
function getMockName(): string;

使用此方法傳回透過 .mockName(name) 方法分配給模擬的名稱。預設情況下,它會傳回 vi.fn()。

mockClear ​

ts
function mockClear(): MockInstance<T>;

清除每次呼叫的所有資訊。呼叫此方法後,.mock 上的所有屬性都將恢復到其初始狀態。此方法不會重置實作。這對於在不同斷言之間清除模擬很有用。

ts
const person = {
  greet: (name: string) => `Hello ${name}`,
};
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked');
expect(person.greet('Alice')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Alice']]);

// clear call history but keep mock implementation
spy.mockClear();
expect(spy.mock.calls).toEqual([]);
expect(person.greet('Bob')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Bob']]);

若要在每次測試之前自動呼叫此方法,請在設定中啟用 clearMocks。

mockName ​

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

設定內部模擬名稱。這在斷言失敗時,有助於識別模擬。

mockImplementation ​

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

接受一個函式作為模擬實作。TypeScript 期望其參數和傳回類型與原始函式相符。

ts
const mockFn = vi.fn().mockImplementation((apples: number) => 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 ​

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

接受一個函式作為模擬實作。TypeScript 期望其參數和傳回類型與原始函式相符。此方法可以串聯,以針對多次函式呼叫產生不同的結果。

ts
const myMockFn = vi
  .fn()
  .mockImplementationOnce(() => true) // 1st call
  .mockImplementationOnce(() => false); // 2nd call

myMockFn(); // 1st call: true
myMockFn(); // 2nd call: 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>>;

在回呼執行期間,暫時覆寫原始模擬實作。

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

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

myMockFn(); // 'original'

可以與非同步回呼一起使用。該方法必須被 await,才能在之後使用原始實作。

ts
test('async callback', async () => {
  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 ​

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

接受一個錯誤,該錯誤會在呼叫非同步函式時被拒絕。

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

await asyncMock(); // throws 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(); // throws Error<'Async error'>

mockReset ​

ts
function mockReset(): MockInstance<T>;

執行 mockClear 的功能,並將內部實作重置為原始函式。 這也會重置所有「一次性」實作。

請注意,重置來自 vi.fn() 的模擬會將實作設定為一個傳回 undefined 的空函式。 重置來自 vi.fn(impl) 的模擬會將實作恢復為 impl。

這對於將模擬重置為其原始狀態很有用。

ts
const person = {
  greet: (name: string) => `Hello ${name}`,
};
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked');
expect(person.greet('Alice')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Alice']]);

// clear call history and reset implementation, but method is still spied
spy.mockReset();
expect(spy.mock.calls).toEqual([]);
expect(person.greet).toBe(spy);
expect(person.greet('Bob')).toBe('Hello Bob');
expect(spy.mock.calls).toEqual([['Bob']]);

若要在每次測試之前自動呼叫此方法,請在設定中啟用 mockReset。

mockRestore ​

ts
function mockRestore(): MockInstance<T>;

執行 mockReset 的功能,並恢復被監視物件的原始描述器。

請注意,恢復來自 vi.fn() 的模擬會將實作設定為一個傳回 undefined 的空函式。 恢復來自 vi.fn(impl) 的模擬會將實作恢復為 impl。

ts
const person = {
  greet: (name: string) => `Hello ${name}`,
};
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked');
expect(person.greet('Alice')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Alice']]);

// clear call history and restore spied object method
spy.mockRestore();
expect(spy.mock.calls).toEqual([]);
expect(person.greet).not.toBe(spy);
expect(person.greet('Bob')).toBe('Hello Bob');
expect(spy.mock.calls).toEqual([]);

若要在每次測試之前自動呼叫此方法,請在設定中啟用 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>;

接受一個值,該值會在每次呼叫模擬函式時傳回。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>;

接受一個值,該值會在每次呼叫模擬函式時傳回。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'], // first call
    ['arg3'], // second call
  ];

mock.lastCall ​

ts
const lastCall: Parameters<T> | undefined;

此屬性包含上次呼叫的參數。如果模擬未被呼叫,它會傳回 undefined。

mock.results ​

ts
interface MockResultReturn<T> {
  type: 'return';
  /**
   * The value that was returned from the function.
   * If function returned a Promise, then this will be a resolved value.
   */
  value: T;
}

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

interface MockResultThrow {
  type: 'throw';
  /**
   * An error that was thrown during function execution.
   */
  value: any;
}

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

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

這是一個陣列,其中包含從函式 傳回 的所有值。陣列中的一個項目是一個具有 type 和 value 屬性的物件。可用類型為:

  • 'return' - 函式傳回而未拋出錯誤。
  • 'throw' - 函式拋出一個值。

value 屬性包含傳回值或拋出的錯誤。如果函式傳回 Promise,則 result 會始終為 'return',即使 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.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[];

此屬性傳回模擬函式的執行順序。它是一個數字陣列,在所有已定義的模擬之間共享。

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

如果模擬是使用 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://vitest.dev/api/mock

以 MIT 授權條款 發布。

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