メインコンテンツへスキップ
バージョン: 29.7

セットアップとティアダウン

非公式ベータ版翻訳

このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →

テストを作成する際、テスト実行前に必要なセットアップ作業やテスト実行後に必要な終了作業が発生することがよくあります。Jestはこのような作業を扱うためのヘルパー関数を提供しています。

繰り返しのセットアップ

複数のテストで繰り返し実行する必要がある作業がある場合、beforeEachafterEachフックを使用できます。

例えば、複数のテストが都市データベースとやり取りする場合を考えてみましょう。各テストの前に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();
});

beforeEachafterEachは、テストが非同期コードを扱う方法と同じ方法で非同期コードを処理できます。つまり、doneパラメータを受け取るか、Promiseを返すかのいずれかです。例えば、initializeCityDatabase()がデータベースの初期化時に解決されるPromiseを返す場合、そのPromiseを返すようにします:

beforeEach(() => {
return initializeCityDatabase();
});

一度だけのセットアップ

場合によっては、ファイルの先頭で一度だけセットアップを行う必要があります。これが非同期処理の場合、インラインで実行できないため特に面倒です。Jestはこのような状況に対処するためにbeforeAllafterAllフックを提供します。

例えば、initializeCityDatabase()clearCityDatabase()の両方がPromiseを返し、都市データベースがテスト間で再利用可能な場合、テストコードを次のように変更できます:

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ハンドラを実行します。これが、セットアップとティアダウンをdescribeブロック内ではなくbefore*およびafter*ハンドラ内で行うべきもう一つの理由です。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

Jestはdescribetestブロックと同様に、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 を試すこともできます。