測試 API 參考文件
以下類型用於下面的型別簽章中
type Awaitable<T> = T | PromiseLike<T>;
type TestFunction = () => Awaitable<void>;
interface TestOptions {
/**
* 如果測試執行時間過長,測試將會失敗
*/
timeout?: number;
/**
* 如果測試失敗,將會重試特定次數
*
* @default 0
*/
retry?: number;
/**
* 即使每次都失敗,也會重複執行相同的測試數次
* 如果您有 "retry" 選項並且它失敗了,它將在每個循環週期中使用每次重試
* 對於調試隨機失敗非常有用
*
* @default 0
*/
repeats?: number;
}當測試函數返回一個 promise 時,執行器程式將等待它被解析以收集非同步期望值。如果 promise 被拒絕,測試將失敗。
TIP
在 Jest 中,TestFunction 也可以是 (done: DoneCallback) => void 類型。如果使用這種形式,測試將不會結束,直到 done 被調用。您可以使用 async 函數實現相同的效果,請參閱 遷移指南 Done Callback 章節。
大多數選項同時支援點語法和物件語法,你可以選擇你喜歡的寫法。
import { test } from 'vitest';
test.skip('skipped test', () => {
// some logic that fails right now
});import { test } from 'vitest';
test('skipped test', { skip: true }, () => {
// some logic that fails right now
});test
- 別名:
it
test 定義了一組相關的期望。它接收測試名稱和一個包含要測試的期望的函數。
您可以選擇性地提供一個超時時間(以毫秒為單位),以指定在終止之前等待的時間。預設值為 5 秒,可以使用 testTimeout 進行全域設定。
import { expect, test } from 'vitest';
test('should work as expected', () => {
expect(Math.sqrt(4)).toBe(2);
});test.extend
- 別名:
it.extend
使用 test.extend 來擴展測試上下文,使其具有自定義測試固定裝置(fixtures)。這將返回一個新的 test 並且也是可擴展的,因此您可以根據需要通過擴展它來組合更多 fixtures 或覆蓋現有的 fixtures。有關更多資訊,請參閱 擴展測試上下文。
import { expect, test } from 'vitest';
const todos = [];
const archive = [];
const myTest = test.extend({
todos: async ({ task }, use) => {
todos.push(1, 2, 3);
await use(todos);
todos.length = 0;
},
archive,
});
myTest('add item', ({ todos }) => {
expect(todos.length).toBe(3);
todos.push(4);
expect(todos.length).toBe(4);
});test.skip
- 別名:
it.skip
如果您想跳過運行某些測試,但基於任何原因不想刪除代碼,您可以使用 test.skip 來避免運行它們。
import { assert, test } from 'vitest';
test.skip('skipped test', () => {
// Test skipped, no error
assert.equal(Math.sqrt(4), 3);
});您還可以通過在其 context 上動態調用 skip 來跳過測試:
import { assert, test } from 'vitest';
test('skipped test', context => {
context.skip();
// Test skipped, no error
assert.equal(Math.sqrt(4), 3);
});test.skipIf
- 別名:
it.skipIf
在某些情況下,您可能會使用不同的環境多次運行測試,並且某些測試可能是特定於環境的。您可以不用 if 包裹測試代碼,改為使用 test.skipIf 在條件為真時跳過測試。
import { assert, test } from 'vitest';
const isDev = process.env.NODE_ENV === 'development';
test.skipIf(isDev)('prod only test', () => {
// this test only runs in production
});WARNING
當使用 Vitest 作為 類型檢查器 時,您不能使用此語法。
test.runIf
- 別名:
it.runIf
與 test.skipIf 相反。
import { assert, test } from 'vitest';
const isDev = process.env.NODE_ENV === 'development';
test.runIf(isDev)('dev only test', () => {
// this test only runs in development
});WARNING
當使用 Vitest 作為 類型檢查器 時,您不能使用此語法。
test.only
- 別名:
it.only
使用 test.only 僅運行給定套件中的某些測試。這在調試時很有用。
您可以選擇性地提供一個超時時間(以毫秒為單位),以指定在終止之前等待的時間。預設值為 5 秒,可以使用 testTimeout 進行全域設定。
import { assert, test } from 'vitest';
test.only('test', () => {
// Only this test (and others marked with only) are run
assert.equal(Math.sqrt(4), 2);
});有時,僅運行特定文件中的 only 測試非常有用,藉此忽略來自整個測試套件的所有其他測試,避免這些測試影響輸出結果。
為了做到這一點,請使用包含相關測試的特定文件運行 vitest。
# vitest interesting.test.tstest.concurrent
- 別名:
it.concurrent
test.concurrent 標記連續的測試以並行運行。它接收測試名稱、一個包含要收集的測試的異步函數和一個可選的超時時間(以毫秒為單位)。
import { describe, test } from 'vitest';
// The two tests marked with concurrent will be run in parallel
describe('suite', () => {
test('serial test', async () => {
/* ... */
});
test.concurrent('concurrent test 1', async () => {
/* ... */
});
test.concurrent('concurrent test 2', async () => {
/* ... */
});
});test.skip、test.only 和 test.todo 適用於並行測試。以下所有組合都是有效的:
test.concurrent(/* ... */);
test.skip.concurrent(/* ... */); // or test.concurrent.skip(/* ... */)
test.only.concurrent(/* ... */); // or test.concurrent.only(/* ... */)
test.todo.concurrent(/* ... */); // or test.concurrent.todo(/* ... */)運行並行測試時,快照檔和斷言檢查必須使用來自本地 測試上下文 的 expect,以確保能檢測到正確的測試。
test.concurrent('test 1', async ({ expect }) => {
expect(foo).toMatchSnapshot();
});
test.concurrent('test 2', async ({ expect }) => {
expect(foo).toMatchSnapshot();
});WARNING
當使用 Vitest 作為 類型檢查器 時,您不能使用此語法。
test.sequential
- 別名:
it.sequential
test.sequential 將一個測試標記為循序執行。如果您想在 describe.concurrent 中或使用 --sequence.concurrent 命令列選項時按順序執行測試,這將非常有用。
import { describe, test } from 'vitest';
// 使用配置選項 { sequence: { concurrent: true } }
test('concurrent test 1', async () => {
/* ... */
});
test('concurrent test 2', async () => {
/* ... */
});
test.sequential('sequential test 1', async () => {
/* ... */
});
test.sequential('sequential test 2', async () => {
/* ... */
});
// 在並行套件中
describe.concurrent('suite', () => {
test('concurrent test 1', async () => {
/* ... */
});
test('concurrent test 2', async () => {
/* ... */
});
test.sequential('sequential test 1', async () => {
/* ... */
});
test.sequential('sequential test 2', async () => {
/* ... */
});
});test.todo
- 別名:
it.todo
使用 test.todo 來建立稍後要實現的測試樁。報告中將顯示測試的項目,以便您知道還需要實現多少測試。
// An entry will be shown in the report for this test
test.todo('unimplemented test');test.fails
- 別名:
it.fails
使用 test.fails 來指示斷言檢查將顯式失敗。
import { expect, test } from 'vitest';
function myAsyncFunc() {
return new Promise(resolve => resolve(1));
}
test.fails('fail test', async () => {
await expect(myAsyncFunc()).rejects.toBe(1);
});WARNING
當使用 Vitest 作為 類型檢查器 時,您不能使用此語法。
test.each
- 別名:
it.each
TIP
test.each 是為了相容 Jest 而提供的,但 Vitest 也提供了 test.for,它額外增加了整合 TestContext 的功能。
當您需要使用不同的變數運行相同的測試時,請使用 test.each。 您可以使用 printf 格式化,依照測試函數參數的順序,在測試名稱中注入參數。
%s: 字串%d: 數字%i: 整數%f: 浮點數值%j: json%o: 物件%#: 測試案例的索引%%: 單個百分號 ('%')
import { expect, test } from 'vitest';
test.each([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])('add(%i, %i) -> %i', (a, b, expected) => {
expect(a + b).toBe(expected);
});
// 這將返回
// ✓ add(1, 1) -> 2
// ✓ add(1, 2) -> 3
// ✓ add(2, 1) -> 3如果您使用物件作為參數,您也可以使用 $ 前綴訪問物件屬性:
test.each([
{ a: 1, b: 1, expected: 2 },
{ a: 1, b: 2, expected: 3 },
{ a: 2, b: 1, expected: 3 },
])('add($a, $b) -> $expected', ({ a, b, expected }) => {
expect(a + b).toBe(expected);
});
// 這將返回
// ✓ add(1, 1) -> 2
// ✓ add(1, 2) -> 3
// ✓ add(2, 1) -> 3如果您使用物件作為參數,您也可以使用 . 訪問物件屬性:
test.each`
a | b | expected
${{ val: 1 }} | ${'b'} | ${'1b'}
${{ val: 2 }} | ${'b'} | ${'2b'}
${{ val: 3 }} | ${'b'} | ${'3b'}
`('add($a.val, $b) -> $expected', ({ a, b, expected }) => {
expect(a.val + b).toBe(expected);
});
// 這將返回
// ✓ add(1, b) -> 1b
// ✓ add(2, b) -> 2b
// ✓ add(3, b) -> 3b從 Vitest 0.25.3 開始,您也可以使用模板字串表。
- 第一行應該是欄位名稱,用
|分隔; - 一個或多個後續的資料列作為使用
${value}語法的模板文字表達式提供。
import { expect, test } from 'vitest';
test.each`
a | b | expected
${1} | ${1} | ${2}
${'a'} | ${'b'} | ${'ab'}
${[]} | ${'b'} | ${'b'}
${{}} | ${'b'} | ${'[object Object]b'}
${{ asd: 1 }} | ${'b'} | ${'[object Object]b'}
`('returns $expected when $a is added $b', ({ a, b, expected }) => {
expect(a + b).toBe(expected);
});TIP
Vitest 使用 chai format 方法處理 $values。如果值被截斷得太厲害,您可以在配置文件中增加 chaiConfig.truncateThreshold。
WARNING
當使用 Vitest 作為 類型檢查器 時,您不能使用此語法。
test.for
- 別名:
it.for
test.each 的另一種替代方案,用於提供 TestContext。
與 test.each 的區別在於陣列情況在參數中的提供方式。 其他非陣列情況(包括模板字串用法)工作方式完全相同。
// `each` 會展開陣列情況
test.each([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])('add(%i, %i) -> %i', (a, b, expected) => {
expect(a + b).toBe(expected);
});
// `for` 不展開陣列情況
test.for([
[1, 1, 2],
[1, 2, 3],
[2, 1, 3],
])('add(%i, %i) -> %i', ([a, b, expected]) => {
expect(a + b).toBe(expected);
});第二個參數是 TestContext,可用於併發快照,例如:
test.concurrent.for([
[1, 1],
[1, 2],
[2, 1],
])('add(%i, %i)', ([a, b], { expect }) => {
expect(a + b).matchSnapshot();
});bench
- 類型:
(name: string | Function, fn: BenchFunction, options?: BenchOptions) => void
bench 定義一個基準測試程式(benchmark)。在 Vitest 的術語中,基準測試是一個定義一系列操作的函數。Vitest 多次運行此函數以顯示不同的性能結果。
Vitest 在底層使用 tinybench 庫,繼承了它的所有選項,這些選項可以用作第三個參數。
import { bench } from 'vitest';
bench(
'normal sorting',
() => {
const x = [1, 5, 4, 2, 3];
x.sort((a, b) => {
return a - b;
});
},
{ time: 1000 }
);export interface Options {
/**
* 運行基準測試任務所需的時間(毫秒)
* @default 500
*/
time?: number;
/**
* 即使 time 選項已完成,任務也應運行的次數
* @default 10
*/
iterations?: number;
/**
* 獲取當前時間戳(以毫秒為單位)的函數
*/
now?: () => number;
/**
* 用於中止基準測試的 AbortSignal
*/
signal?: AbortSignal;
/**
* 如果任務失敗則拋出錯誤(如果為 true,則事件將不起作用)
*/
throws?: boolean;
/**
* 暖機時間(毫秒)
* @default 100ms
*/
warmupTime?: number;
/**
* 暖機迭代次數
* @default 5
*/
warmupIterations?: number;
/**
* 在每個基準測試任務(循環週期)之前運行的設置函數
*/
setup?: Hook;
/**
* 在每個基準測試任務(循環週期)之後運行的拆卸函式
*/
teardown?: Hook;
}測試用例運行後,輸出結構資訊如下:
name hz min max mean p75 p99 p995 p999 rme samples
· normal sorting 6,526,368.12 0.0001 0.3638 0.0002 0.0002 0.0002 0.0002 0.0004 ±1.41% 652638export interface TaskResult {
/*
* 運行任務時拋出的最後一個錯誤
*/
error?: unknown;
/**
* 運行基準測試任務(週期)所需的時間(毫秒)。
*/
totalTime: number;
/**
* 範本中的最小值
*/
min: number;
/**
* 範本中的最大值
*/
max: number;
/**
* 每秒操作數
*/
hz: number;
/**
* 每次操作花費的時間(毫秒)
*/
period: number;
/**
* 每個任務疊代時間的任務範本(毫秒)
*/
samples: number[];
/**
* 範本均值/平均值(總體均值的估計)
*/
mean: number;
/**
* 範本方差(總體方差的估計)
*/
variance: number;
/**
* 範本標準差(總體標準差的估計)
*/
sd: number;
/**
* 均值的標準誤差(也稱為範本均值抽樣分佈的標準差)
*/
sem: number;
/**
* 自由度
*/
df: number;
/**
* 範本的臨界值
*/
critical: number;
/**
* 誤差範圍
*/
moe: number;
/**
* 相對誤差範圍
*/
rme: number;
/**
* 中位數絕對偏差
*/
mad: number;
/**
* p50/中位數百分位
*/
p50: number;
/**
* p75 百分位
*/
p75: number;
/**
* p99 百分位
*/
p99: number;
/**
* p995 百分位
*/
p995: number;
/**
* p999 百分位
*/
p999: number;
}bench.skip
- 類型:
(name: string | Function, fn: BenchFunction, options?: BenchOptions) => void
您可以使用 bench.skip 語法來跳過運行某些基準測試。
import { bench } from 'vitest';
bench.skip('normal sorting', () => {
const x = [1, 5, 4, 2, 3];
x.sort((a, b) => {
return a - b;
});
});bench.only
- 類型:
(name: string | Function, fn: BenchFunction, options?: BenchOptions) => void
使用 bench.only 僅運行給定套件中的某些基準測試。這在調試時很有用。
import { bench } from 'vitest';
bench.only('normal sorting', () => {
const x = [1, 5, 4, 2, 3];
x.sort((a, b) => {
return a - b;
});
});bench.todo
- 類型:
(name: string | Function) => void
使用 bench.todo 來建立稍後要實現的基準測試樁。
import { bench } from 'vitest';
bench.todo('unimplemented test');describe
當你在檔案的最上層使用 test 或 bench 時,它們會被收集為該檔案隱含的測試套件(suite)的一部分。使用 describe 你可以在目前的上下文中定義一個新的測試套件,作為一組相關的測試或基準測試,以及其他巢狀的測試套件。一個測試套件可以讓你組織你的測試和基準測試,使報告更加清晰。
// basic.spec.ts
// 組織測試
import { describe, expect, test } from 'vitest';
const person = {
isActive: true,
age: 32,
};
describe('person', () => {
test('person is defined', () => {
expect(person).toBeDefined();
});
test('is active', () => {
expect(person.isActive).toBeTruthy();
});
test('age limit', () => {
expect(person.age).toBeLessThanOrEqual(32);
});
});// basic.bench.ts
// 組織基準測試
import { bench, describe } from 'vitest';
describe('sort', () => {
bench('normal', () => {
const x = [1, 5, 4, 2, 3];
x.sort((a, b) => {
return a - b;
});
});
bench('reverse', () => {
const x = [1, 5, 4, 2, 3];
x.reverse().sort((a, b) => {
return a - b;
});
});
});如果你有一個測試或基準測試的階層結構,你也可以巢狀 describe 測試套件:
import { describe, expect, test } from 'vitest';
function numberToCurrency(value: number | string) {
if (typeof value !== 'number') {
throw new TypeError('Value must be a number');
}
return value
.toFixed(2)
.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
describe('numberToCurrency', () => {
describe('given an invalid number', () => {
test('composed of non-numbers to throw error', () => {
expect(() => numberToCurrency('abc')).toThrowError();
});
});
describe('given a valid number', () => {
test('returns the correct currency format', () => {
expect(numberToCurrency(10000)).toBe('10,000.00');
});
});
});describe.skip
- Alias:
suite.skip
在一個測試套件中使用 describe.skip 來避免執行特定的 describe 測試套件。
import { assert, describe, test } from 'vitest';
describe.skip('skipped suite', () => {
test('sqrt', () => {
// 測試套件已略過,沒有錯誤
assert.equal(Math.sqrt(4), 3);
});
});describe.skipIf
- Alias:
suite.skipIf
在某些情況下,你可能會在不同環境中多次運行測試套件,並且某些測試套件可能是環境專屬的。你可以使用 describe.skipIf 來跳過測試套件,只要條件為真值,而不需要用 if 包裹測試套件。
import { describe, test } from 'vitest';
const isDev = process.env.NODE_ENV === 'development';
describe.skipIf(isDev)('prod only test', () => {
// 此測試僅在生產環境中執行
});WARNING
當使用 Vitest 作為類型檢查器時,你不能使用此語法。
describe.runIf
- 別名:
suite.runIf
與 describe.skipIf 相反。
import { assert, describe, test } from 'vitest';
const isDev = process.env.NODE_ENV === 'development';
describe.runIf(isDev)('dev only test suite', () => {
// this test suite only runs in development
});WARNING
當使用 Vitest 作為類型檢查器時,您不能使用此語法。
describe.only
- 類型:
(name: string | Function, fn: TestFunction, options?: number | TestOptions) => void
使用 describe.only 僅運行特定的測試套件。
import { assert, describe, test } from 'vitest';
// 僅執行此測試套件(以及其他標記為 `only` 的測試套件)
describe.only('suite', () => {
test('sqrt', () => {
assert.equal(Math.sqrt(4), 3);
});
});
describe('other suite', () => {
// ... 將被跳過
});有時,在特定檔案中運行 only 測試非常有用,忽略整個測試套件中的所有其他測試,這些測試會影響輸出結果。
為了做到這一點,請使用包含相關測試的特定檔案執行 vitest。
# vitest interesting.test.tsdescribe.concurrent
- Alias:
suite.concurrent
describe.concurrent 平行執行所有內部測試套件和測試
import { describe, test } from 'vitest';
// 此測試套件內的所有測試套件和測試將平行執行
describe.concurrent('suite', () => {
test('concurrent test 1', async () => {
/* ... */
});
describe('concurrent suite 2', async () => {
test('concurrent test inner 1', async () => {
/* ... */
});
test('concurrent test inner 2', async () => {
/* ... */
});
});
test.concurrent('concurrent test 3', async () => {
/* ... */
});
});.skip、.only 和 .todo 適用於並行測試套件。以下所有組合都是有效的:
describe.concurrent(/* ... */);
describe.skip.concurrent(/* ... */); // or describe.concurrent.skip(/* ... */)
describe.only.concurrent(/* ... */); // or describe.concurrent.only(/* ... */)
describe.todo.concurrent(/* ... */); // or describe.concurrent.todo(/* ... */)當執行並行測試時,快照(Snapshots)和斷言(Assertions)必須使用來自本地測試環境的 expect,以確保檢測到正確的測試。
describe.concurrent('suite', () => {
test('concurrent test 1', async ({ expect }) => {
expect(foo).toMatchSnapshot();
});
test('concurrent test 2', async ({ expect }) => {
expect(foo).toMatchSnapshot();
});
});WARNING
當使用 Vitest 作為類型檢查器時,你不能使用此語法。
describe.sequential
- Alias:
suite.sequential
describe.sequential 會將測試套件中的每個測試標記為循序(sequential)。如果你想在 describe.concurrent 中或使用 --sequence.concurrent 命令選項循序執行測試,這非常有用。
import { describe, test } from 'vitest';
describe.concurrent('suite', () => {
test('concurrent test 1', async () => {
/* ... */
});
test('concurrent test 2', async () => {
/* ... */
});
describe.sequential('', () => {
test('sequential test 1', async () => {
/* ... */
});
test('sequential test 2', async () => {
/* ... */
});
});
});describe.shuffle
- Alias:
suite.shuffle
Vitest 提供了一種通過 CLI 標誌 --sequence.shuffle 或配置選項 sequence.shuffle 以隨機順序執行所有測試的方法,但如果你只想讓部分測試套件以隨機順序執行,可以使用此標記。
import { describe, test } from 'vitest';
describe.shuffle('suite', () => {
test('random test 1', async () => {
/* ... */
});
test('random test 2', async () => {
/* ... */
});
test('random test 3', async () => {
/* ... */
});
});
// 順序取決於配置中的 sequence.seed 選項(預設為 Date.now()).skip、.only 和 .todo 適用於隨機測試套件。
WARNING
當使用 Vitest 作為類型檢查器時,你不能使用此語法。
describe.todo
- Alias:
suite.todo
使用 describe.todo 來預留稍後要實作的測試套件。報告中會顯示測試項目,方便你了解尚有多少測試需要實作。
// 將在報告中顯示此測試套件的條目
describe.todo('unimplemented suite');describe.each
- Alias:
suite.each
如果你有多個測試依賴於相同的數據,請使用 describe.each。
import { describe, expect, test } from 'vitest';
describe.each([
{ a: 1, b: 1, expected: 2 },
{ a: 1, b: 2, expected: 3 },
{ a: 2, b: 1, expected: 3 },
])('describe object add($a, $b)', ({ a, b, expected }) => {
test(`returns ${expected}`, () => {
expect(a + b).toBe(expected);
});
test(`returned value not be greater than ${expected}`, () => {
expect(a + b).not.toBeGreaterThan(expected);
});
test(`returned value not be less than ${expected}`, () => {
expect(a + b).not.toBeLessThan(expected);
});
});從 Vitest 0.25.3 開始,你也可以使用模板字串表格。
- 第一行應該是列名,用
|分隔; - 一個或多個後續的數據行,使用
${value}語法作為模板字面量表達式提供。
import { describe, expect, test } from 'vitest';
describe.each`
a | b | expected
${1} | ${1} | ${2}
${'a'} | ${'b'} | ${'ab'}
${[]} | ${'b'} | ${'b'}
${{}} | ${'b'} | ${'[object Object]b'}
${{ asd: 1 }} | ${'b'} | ${'[object Object]b'}
`('describe template string add($a, $b)', ({ a, b, expected }) => {
test(`returns ${expected}`, () => {
expect(a + b).toBe(expected);
});
});WARNING
當使用 Vitest 作為類型檢查器時,你不能使用此語法。
設定與拆卸 (Setup and Teardown)
這些函式允許你鉤入測試的生命週期,以避免重複設定和拆卸程式碼。它們適用於目前的上下文:如果在最上層使用它們,則適用於檔案;如果在 describe 測試套件內使用它們,則適用於目前的測試套件。當你將 Vitest 作為類型檢查器執行時,不會呼叫這些鉤點。
beforeEach
- 類型:
beforeEach(fn: () => Awaitable<void>, timeout?: number)
註冊一個回呼函式,此函式會在目前上下文中每個測試執行前被呼叫。 如果該函式返回一個 Promise,Vitest 會等待 Promise 解析後再執行測試。
你可以選擇性地傳遞逾時時間 (毫秒),設定終止前的等待時間。預設值為 5 秒。
import { beforeEach } from 'vitest';
beforeEach(async () => {
// 在每次測試執行前清除模擬資料並新增一些測試資料
await stopMocking();
await addUser({ name: 'John' });
});在這裡,beforeEach 確保為每個測試添加使用者。
beforeEach 也接受一個可選的清除函式(相當於 afterEach)。
import { beforeEach } from 'vitest';
beforeEach(async () => {
// 在每次測試執行之前呼叫一次
await prepareSomething();
// 清除函式,在每次測試執行之後呼叫一次
return async () => {
await resetSomething();
};
});afterEach
- 類型:
afterEach(fn: () => Awaitable<void>, timeout?: number)
註冊一個回呼函式,此函式會在目前上下文中每個測試完成後被呼叫。 如果該函式返回一個 Promise,Vitest 會等待 Promise 解析後再繼續。
你可以選擇性地提供逾時時間 (毫秒),用於指定終止前的等待時間。預設值為 5 秒。
import { afterEach } from 'vitest';
afterEach(async () => {
await clearTestingData(); // 在每次測試執行後清除測試資料
});在這裡,afterEach 確保在每次測試執行後清除測試資料。
TIP
Vitest 1.3.0 新增了 onTestFinished hook。您可以在測試執行期間呼叫它,以便在測試執行結束後清除任何狀態。
beforeAll
- 類型:
beforeAll(fn: () => Awaitable<void>, timeout?: number)
註冊一個回呼函式,此函式會在開始執行目前上下文中所有測試前被呼叫一次。 如果該函式返回一個 Promise,Vitest 會等待 Promise 解析後再執行測試。
你可以選擇性地提供逾時時間 (毫秒),用於指定終止前的等待時間。預設值為 5 秒。
import { beforeAll } from 'vitest';
beforeAll(async () => {
await startMocking(); // 在所有測試執行之前呼叫一次
});在此,beforeAll 確保在測試執行前設定模擬資料。
beforeAll 也接受一個可選的清除函式(相當於 afterAll)。
import { beforeAll } from 'vitest';
beforeAll(async () => {
// 在所有測試執行之前呼叫一次
await startMocking();
// 清除函式,在所有測試執行之後呼叫一次
return async () => {
await stopMocking();
};
});afterAll
- 類型:
afterAll(fn: () => Awaitable<void>, timeout?: number)
註冊一個回呼函式,此函式會在目前上下文中所有測試執行完畢後被呼叫一次。 如果該函式返回一個 Promise,Vitest 會等待 Promise 解析後再繼續。
你可以選擇性地提供逾時時間 (毫秒),用於指定終止前的等待時間。預設值為 5 秒。
import { afterAll } from 'vitest';
afterAll(async () => {
await stopMocking(); // 此方法在所有測試執行完畢後呼叫
});在此,afterAll 確保在所有測試執行完畢後呼叫 stopMocking 函式。
測試鉤子
Vitest 提供了一些鉤子,你可以在測試執行期間呼叫它們,以便在測試運行完畢後清理狀態。
WARNING
如果在測試主體之外呼叫這些鉤子,將會拋出錯誤。
onTestFinished
此鉤子總是在測試運行完畢後呼叫。 它在 afterEach 鉤子之後呼叫,因為它們可能會影響測試結果。 它接收一個 TaskResult 物件,其中包含目前的測試結果。
import { onTestFinished, test } from 'vitest';
test('執行查詢', () => {
const db = connectDb();
onTestFinished(() => db.close());
db.query('SELECT * FROM users');
});WARNING
如果正在並發執行測試,則應始終使用測試內容中的 onTestFinished 鉤子,因為 Vitest 不會在全域鉤子中追蹤並發測試:
import { test } from 'vitest';
test.concurrent('執行查詢', ({ onTestFinished }) => {
const db = connectDb();
onTestFinished(() => db.close());
db.query('SELECT * FROM users');
});此鉤子在建立可重複使用邏輯時特別有用:
// 這可以放在單獨的檔案中
function getTestDb() {
const db = connectMockedDb();
onTestFinished(() => db.close());
return db;
}
test('執行使用者查詢', async () => {
const db = getTestDb();
expect(await db.query('SELECT * from users').perform()).toEqual([]);
});
test('執行組織查詢', async () => {
const db = getTestDb();
expect(await db.query('SELECT * from organizations').perform()).toEqual([]);
});TIP
此鉤子始終以相反的順序呼叫,並且不受 sequence.hooks 選項的影響。
onTestFailed
此鉤子僅在測試失敗後呼叫。 它在 afterEach 鉤子之後呼叫,因為它們可能會影響測試結果。 它接收一個 TaskResult 物件,其中包含目前的測試結果。 此鉤子對於偵錯很有用。
import { onTestFailed, test } from 'vitest';
test('執行查詢', () => {
const db = connectDb();
onTestFailed(e => {
console.log(e.result.errors);
});
db.query('SELECT * FROM users');
});WARNING
如果正在並發執行測試,則應始終使用測試內容中的 onTestFailed 鉤子,因為 Vitest 不會在全域鉤子中追蹤並發測試:
import { test from 'vitest'
test.concurrent('執行查詢', ({ onTestFailed }) => {
const db = connectDb()
onTestFailed((result) => {
console.log(result.errors)
})
db.query('SELECT * FROM users')
})