設定和結束
在撰寫測試時,通常會有一些設定工作需要在測試執行前進行,還有一些結束工作需要在測試執行後進行。Jest 提供了輔助函式來處理這項工作。
重複設定
如果您有一些工作需要重複執行多次測試,可以使用 beforeEach
和 afterEach
鉤子。
例如,假設有幾個測試與城市資料庫進行互動。您有一個方法 initializeCityDatabase()
,必須在這些測試的每個測試之前呼叫,還有一個方法 clearCityDatabase()
,必須在這些測試的每個測試之後呼叫。您可以使用下列方式執行此操作
beforeEach(() => {
initializeCityDatabase();
});
afterEach(() => {
clearCityDatabase();
});
test('city database has Vienna', () => {
expect(isCity('Vienna')).toBeTruthy();
});
test('city database has San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});
beforeEach
和 afterEach
可以處理非同步程式碼,其方式與 測試處理非同步程式碼 的方式相同,它們可以採用 done
參數或傳回承諾。例如,如果 initializeCityDatabase()
傳回一個承諾,在資料庫初始化時解析,我們會希望傳回該承諾
beforeEach(() => {
return initializeCityDatabase();
});
一次性設定
在某些情況下,您只需要在檔案開頭進行一次設定。當設定是非同步時,這可能會特別麻煩,因此您無法內嵌執行。Jest 提供了 beforeAll
和 afterAll
鉤子來處理這種情況。
例如,如果 initializeCityDatabase()
和 clearCityDatabase()
都傳回承諾,且城市資料庫可以在測試之間重複使用,我們可以將測試程式碼變更為
beforeAll(() => {
return initializeCityDatabase();
});
afterAll(() => {
return clearCityDatabase();
});
test('city database has Vienna', () => {
expect(isCity('Vienna')).toBeTruthy();
});
test('city database has San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});
範圍
頂層的 before*
和 after*
掛鉤套用於檔案中的每個測試。在 describe
區塊內宣告的掛鉤只套用於該 describe
區塊內的測試。
例如,假設我們不僅有城市資料庫,還有食物資料庫。我們可以為不同的測試執行不同的設定
// Applies to all tests in this file
beforeEach(() => {
return initializeCityDatabase();
});
test('city database has Vienna', () => {
expect(isCity('Vienna')).toBeTruthy();
});
test('city database has San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});
describe('matching cities to foods', () => {
// Applies only to tests in this describe block
beforeEach(() => {
return initializeFoodDatabase();
});
test('Vienna <3 veal', () => {
expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);
});
test('San Juan <3 plantains', () => {
expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
});
});
請注意,頂層的 beforeEach
會在 describe
區塊內的 beforeEach
之前執行。這有助於說明所有掛鉤的執行順序。
beforeAll(() => console.log('1 - beforeAll'));
afterAll(() => console.log('1 - afterAll'));
beforeEach(() => console.log('1 - beforeEach'));
afterEach(() => console.log('1 - afterEach'));
test('', () => console.log('1 - test'));
describe('Scoped / Nested block', () => {
beforeAll(() => console.log('2 - beforeAll'));
afterAll(() => console.log('2 - afterAll'));
beforeEach(() => console.log('2 - beforeEach'));
afterEach(() => console.log('2 - afterEach'));
test('', () => console.log('2 - test'));
});
// 1 - beforeAll
// 1 - beforeEach
// 1 - test
// 1 - afterEach
// 2 - beforeAll
// 1 - beforeEach
// 2 - beforeEach
// 2 - test
// 2 - afterEach
// 1 - afterEach
// 2 - afterAll
// 1 - afterAll
執行順序
Jest 會在執行任何實際測試之前執行測試檔案中的所有 describe 處理常式。這是另一個原因,說明在 before*
和 after*
處理常式內而非 describe
區塊內執行設定和清除。一旦 describe
區塊完成,預設情況下,Jest 會按收集階段遇到的順序依序執行所有測試,並等到每個測試完成並整理完畢後才繼續進行。
考慮以下說明性的測試檔案和輸出
describe('describe outer', () => {
console.log('describe outer-a');
describe('describe inner 1', () => {
console.log('describe inner 1');
test('test 1', () => console.log('test 1'));
});
console.log('describe outer-b');
test('test 2', () => console.log('test 2'));
describe('describe inner 2', () => {
console.log('describe inner 2');
test('test 3', () => console.log('test 3'));
});
console.log('describe outer-c');
});
// describe outer-a
// describe inner 1
// describe outer-b
// describe inner 2
// describe outer-c
// test 1
// test 2
// test 3
就像 describe
和 test
區塊一樣,Jest 會按宣告順序呼叫 before*
和 after*
掛鉤。請注意,會先呼叫封閉範圍的 after*
掛鉤。例如,以下是如何設定和清除彼此依賴的資源
beforeEach(() => console.log('connection setup'));
beforeEach(() => console.log('database setup'));
afterEach(() => console.log('database teardown'));
afterEach(() => console.log('connection teardown'));
test('test 1', () => console.log('test 1'));
describe('extra', () => {
beforeEach(() => console.log('extra database setup'));
afterEach(() => console.log('extra database teardown'));
test('test 2', () => console.log('test 2'));
});
// connection setup
// database setup
// test 1
// database teardown
// connection teardown
// connection setup
// database setup
// extra database setup
// test 2
// extra database teardown
// database teardown
// connection teardown
如果您使用 jasmine2
測試執行器,請考慮它會以相反的宣告順序呼叫 after*
掛鉤。若要產生相同的輸出,上述範例應修改如下
beforeEach(() => console.log('connection setup'));
+ afterEach(() => console.log('connection teardown'));
beforeEach(() => console.log('database setup'));
+ afterEach(() => console.log('database teardown'));
- afterEach(() => console.log('database teardown'));
- afterEach(() => console.log('connection teardown'));
// ...
一般建議
如果測試失敗,首先要檢查的事情之一是,當測試是唯一執行的測試時,測試是否會失敗。若要使用 Jest 僅執行一個測試,請暫時將 test
指令變更為 test.only
test.only('this will be the only test that runs', () => {
expect(true).toBe(false);
});
test('this test will not run', () => {
expect('A').toBe('A');
});
如果您有一個測試在作為較大套件的一部分執行時經常失敗,但單獨執行時不會失敗,那麼很可能來自不同測試的某些內容會干擾這個測試。您通常可以透過使用 beforeEach
清除一些共用狀態來修正此問題。如果您不確定是否修改了一些共用狀態,您也可以嘗試記錄資料的 beforeEach
。