セットアップと破棄
テストを書いている際にしばしば、テストを実行する前にいくつかのセットアップ作業をしたり、テストが終了した後にいくつかの仕上げ作業をしたい場合があります。 Jest はこれらを処理するヘルパー機能を提供します。
テストごとにセットアップ作業を繰り返し実行する
多くのテストで繰り返し行う必要がある場合は、beforeEach
と afterEach
を使用します。
たとえば、いくつかのテストが City のデータベースと関係するとしましょう。 そしてこれらのテストの前に 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
は非同期コードをテストする と同様に非同期コードを扱えます - promise を返すか done
パラメータのどちらかを選択します。 たとえば、もし initializeCityDatabase()
が promiseを返すのであれば、データベースが初期化された際には promise が返されることが望まれます。
beforeEach(() => {
return initializeCityDatabase();
});
ワンタイムセットアップ
セットアップがファイルの先頭で一回だけ実行されることが必要なケースがあります。 このセットアップが非同期で行われる場合は特に面倒になるので、インラインでは実施できません。 Jest はこの状況に対応するために beforeAll
と afterAll
を提供しています。
たとえば、initializeCityDatabase
と clearCityDatabase
が Promise オブジェクトを返し、City データベースがテスト間で再利用される場合、テストコードを以下のように変更することができます。
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();
});
スコープ
The top level before*
and after*
hooks apply to every test in a file. The hooks declared inside a describe
block apply only to the tests within that describe
block.
たとえば、都市データベースだけでなく、食品データベースもあるとします。 テストごとに異なるセットアップを行うことができます:
// 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
describe ブロックと test ブロックの実行順序
Jest は、テストファイル内のすべての describe ハンドラを、実際のすべてのテストを実行する前に実行します。 これが、セットアップとティアダウンを describe ブロックではなく、before*
および after*
ハンドラの中で実行するもう一つの理由です。 describe ブロックの実行完了後に、デフォルトでは、 Jest はコレクションフェーズで発見したテストを順番に直列に実行します。 次のテストに移動する前に、それぞれのテストが完了して片付けが終わるまで待ちます。
次のような説明のためのテストファイルとその出力について見てみましょう。
describe('outer', () => {
console.log('describe outer-a');
describe('describe inner 1', () => {
console.log('describe inner 1');
test('test 1', () => {
console.log('test for describe inner 1');
expect(true).toBe(true);
});
});
console.log('describe outer-b');
test('test 1', () => {
console.log('test for describe outer');
expect(true).toBe(true);
});
describe('describe inner 2', () => {
console.log('describe inner 2');
test('test for describe inner 2', () => {
console.log('test for describe inner 2');
expect(false).toBe(false);
});
});
console.log('describe outer-c');
});
// describe outer-a
// describe inner 1
// describe outer-b
// describe inner 2
// describe outer-c
// test for describe inner 1
// test for describe outer
// test for describe inner 2
一般的なアドバイス
もしテストが失敗して、まず最初に調べるべきことの一つはそのテストが単体で実行された場合にも失敗するかどうかということです。 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
を使ってデータのログを取得することもできます。