この記事では、Jestの基本的な使い方をざっくり説明します。Jestの主要機能を確認したい、Jestの雰囲気をつかみたいといった方向けです。Jestをより詳しく知りたい場合は、公式ドキュメントをご確認ください。
Jestとは
- Jestはシンプルさを重視したJavaScriptのテスティングフレームワークです。
- 哲学として「テストを楽しくする」が掲げられています。
- Jestは、TypeScript, Node, React, Angular, Vueなどさまざまなプロジェクトで利用できます。
Jestの特徴は次の通りです。
- 設定なしで導入できる
- テストを並列で実行するので速い
- モックが簡単
- フラグを追加するだけでコードカバレッジを計測できる
Jestでテストを書く
describe
メソッドでいくつかの関連するテストをまとめます。- そして、
test
メソッド(別名のit
メソッドもある)で、テストケースを記載します。 - テストケース内では、
expect
とMatcherを使ってアサーションをします。 - Matcherは
toBe()
やtoEqual()
などテスト対象の値を比較をするメソッドです。
// sum.js // テスト対象のコード function sum(a, b) { return a + b; } module.exports = sum; // sum.test.js // テストコード const sum = require('./sum'); describe('sum', () => { it('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); }); it('adds -1 + 2 to equal 1', () => { expect(sum(-1, 2)).toBe(1); }); });
JestのMatcherを使いこなす
- Jestでは
expect
で検証します。 .not
をメソッドチェインすることで否定を表せます。- さまざまな種類のMatcherがあるのでテストケースの実装で困ることはほぼないでしょう。
- 参考: Jestで利用できるMatchers
describe('sum', () => { it('should not return null', () => { expect(sum(1, 2)).not.toBeNull(); }); });
Jestで非同期処理のテストコードを書く
- Jestで非同期処理のテストをする方法はいくつかありますが、
async/await
を使うと良いでしょう。 - 他のテストの書き方としては、
then/catch
でテストする方法、.resolves
/.rejects
でテストする方法などがあります。
test
の関数をasync
キーワードで定義し、await
で非同期処理を待ちます。
// Async/Awaitで非同期処理をテスト // テスト対象の非同期処理のコード const fetchUser = async (id) => { return new Promise((resolve, reject) => { setTimeout(() => { // テストのためのダミー実装 if (id === 1) { resolve('John Doe'); } else { reject('not found user'); } }, 200); }); } // テストコード describe('fetchUser', () => { // 非同期処理が成功するケース test('the data is John Doe', async () => { const user = await fetchUser(1); expect(user).toBe('John Doe'); }); // 非同期処理が失敗するケース test('the fetch fails with an error', async () => { await expect(fetchUser(2)).rejects.toMatch('not found user'); }); });
Jestでモックを使う
- モックする方法は、「テストコード中でモック関数を作成する方法」と「マニュアルモックを使う方法」の2つがあります。
- ここでは、「テストコード中でモック関数を作成する方法」を説明します。
- モジュールのモックをクリアするには、Jestの設定ファイルでclearMocksを
true
にすると良いでしょう。
Jestのモックはjest.fn()
で作成し、mockReturnValue()
やmockImplementation()
でモックの返り値の指定やモックの振る舞いを実装できます。
// jest.fn()でモックを作成 // mockReturnValue()でモックの返り値を指定できる test('the mock returns 10', () => { const myMock = jest.fn().mockReturnValue(10); expect(myMock()).toBe(10); }); // mockReturnValueOnce()で呼び出し回数に応じてモックの返り値を変えることができる test('the mock returns 10, "x", false', () => { const myMock = jest.fn() .mockReturnValueOnce(10) .mockReturnValueOnce('x') .mockReturnValueOnce(false); expect(myMock()).toBe(10); expect(myMock()).toBe('x'); expect(myMock()).toBe(false); }); // mockImplementation()でモックの振る舞いを実装できる test('the mock adds a and b', () => { const myAddMock = jest.fn() .mockImplementation((a, b) => a + b); expect(myAddMock(1, 3)).toBe(4); });
また、外部のモジュールをモックしたい場合はjest.mock()
を使います。
// users.js import axios from 'axios'; class Users { static all() { return axios.get('/users.json').then(resp => resp.data); } } export default Users; // users.test.js import axios from 'axios'; import Users from './users'; jest.mock('axios'); it('should fetch users', async () => { const users = [{ name: 'Bob' }]; const resp = { data: users }; axios.get.mockResolvedValue(resp); // もしくは mockImplementationで次のように実装可能 // axios.get.mockImplementation(() => Promise.resolve(resp)) const data = await Users.all() expect(data).toEqual(users); });
テストのSetupとTeardown
beforeEach()
で各テストケースのセットアップ処理を共通化することができます。afterEach()
で各テストケースの終了後の処理を共通化することができます。beforeAll()
やafterAll()
を使うことでテストケースのまとまりに応じてセットアップや終了後の処理を記載できます。
describe('isCity', () => { // 各テストケースの実行前に実行される beforeEach(() => { initializeCityDatabase(); }); // 各テストケースの終了後に実行される afterEach(() => { clearCityDatabase(); }); test('city database has Vienna', () => { expect(isCity('Vienna')).toBeTruthy(); }); test('city database has San Juan', () => { expect(isCity('San Juan')).toBeTruthy(); }); });