跳到內容

模擬函式

您可以使用 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
const  = .().( =>  + 1)
// or: vi.fn(apples => apples + 1);

const  = (0)
const  = (1)

 === 1 // true
 === 2 // true

..[0][0] === 0 // true
..[1][0] === 1 // true

mockImplementationOnce

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

接受一個函式,將用作模擬的下一次呼叫的實作。可以串接,讓多個函式呼叫產生不同的結果。

ts
const  = 
  .()
  .(() => true)
  .(() => false)

() // true
() // false

當模擬函式用完實作時,它會呼叫預設實作,預設實作是使用 vi.fn(() => defaultValue).mockImplementation(() => defaultValue) 設定的(如果已呼叫)

ts
const  = 
  .(() => 'default')
  .(() => 'first call')
  .(() => 'second call')

// 'first call', 'second call', 'default', 'default'
.((), (), (), ())

withImplementation

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

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

js
const  = .(() => 'original')

.(() => 'temp', () => {
  () // 'temp'
})

() // '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

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

ts
const  = .().(new ('Async error'))

await () // throws "Async error"

mockRejectedValueOnce

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

接受一個值,在下一次函式呼叫時會被拒絕。如果串接,每個連續呼叫都會拒絕指定的值。

ts
const  = 
  .()
  .('first call')
  .(new ('Async error'))

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

mockReset

  • 類型: () => MockInstance

執行 mockClear 的動作,並將內部實作設為空函式(呼叫時傳回 undefined)。這也會重設所有「一次性」實作。當您想要將模擬完全重設為預設狀態時,這很有用。

如果您希望在每個測試之前自動呼叫此方法,可以在設定中啟用 mockReset 設定。

mockRestore

  • 類型: () => MockInstance

執行 mockReset 的動作,並將內部實作還原至原始函式。

請注意,從 vi.fn() 還原 mock 將會將實作設定為一個傳回 undefined 的空函式。還原 vi.fn(impl) 將會將實作還原至 impl

如果你希望這個方法在每個測試前自動呼叫,你可以啟用設定中的 restoreMocks

mockResolvedValue

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

接受一個值,當非同步函式被呼叫時將會解析此值。

ts
const  = .().(42)

await () // 42

mockResolvedValueOnce

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

接受一個值,將會在下次函式呼叫時解析此值。如果串接,每個連續呼叫都將解析指定的數值。

ts
const  = 
  .()
  .('default')
  .('first call')
  .('second call')

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

mockReturnThis

  • 類型: () => MockInstance

如果你需要從方法中傳回 this 內容,而不呼叫實際實作,請使用這個。這是

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

mockReturnValue

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

接受一個值,每當呼叫 mock 函式時都會傳回此值。

ts
const  = .()
.(42)
() // 42
.(43)
() // 43

mockReturnValueOnce

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

接受一個值,將會在下次函式呼叫時傳回此值。如果串接,每個連續呼叫都將傳回指定的數值。

當沒有更多 mockReturnValueOnce 值可以使用時,如果存在先前定義的實作,mock 將會回退至該實作。

ts
const  = 
  .()
  .('default')
  .('first call')
  .('second call')

// 'first call', 'second call', 'default', 'default'
.((), (), (), ())

mock.calls

這是一個陣列,包含每個呼叫的所有引數。陣列中的一個項目是該呼叫的引數。

js
const fn = vi.fn()

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

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

mock.lastCall

這包含最後一次呼叫的引數。如果 mock 沒有被呼叫,將會傳回 undefined

mock.results

這是包含函式returned所有值的陣列。陣列的一個項目是一個具有屬性typevalue的物件。可用的類型為

  • 'return' - 函式在未擲回任何值的情況下傳回。
  • 'throw' - 函式擲回一個值。

value屬性包含傳回的值或擲回的錯誤。如果函式傳回一個 Promise,則value將會是已解決的值,而不是實際的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

mock 執行的順序。這會傳回一個數字陣列,這些數字在所有已定義的 mock 之間共用。

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

fn1()
fn2()
fn1()

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

mock.instances

這是包含在使用new關鍵字呼叫 mock 時所實例化的所有實例的陣列。請注意,這是函式的實際內容 (this),而不是傳回值。

警告

如果使用new MyClass()實例化 mock,則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