Jest とは
Jest は Facebook が公開した JavaScript 用のシンプルなテストフレームワークで、Node.js 環境で実行することができます。
Jest は下記のような特徴を持っています。
- ゼロコンフィグで使い始められる(設定ファイルなしで実行可能)
- テストを並列実行するので高速
- コードカバレッジレポートの出力を標準搭載
- わかりやすいマッチャー表現 (expect ~ toBe、toContain など、自然な文章として読める)
- TypeScript に対応(ts-jest を利用)
Jest 用のテストコードは、次のようなコードジェネレーターでも採用されており、利用者は増え続けています(2022 年現在)。
create-react-app
… React アプリのジェネレーターcdk init app
… AWS のインフラ生成コードのジェネレーター
Jest のインストール
Jest 本体の jest
モジュールをインストールします。
TypeScript を使用する場合は、Jest ライブラリの型情報である @types/jest
と、Jest 用の TypeScript プロセッサ (ts-jest) もインストールする必要があります。
これらはすべてテスト時のみ使用する NPM モジュールなので、devDependencies
としてインストールします。
package.json の修正
Jest によるテストを簡単に起動できるように、package.json
に NPM スクリプト (test
) を定義しておきます。
あと、Jest が TypeScript のコードを理解できるように、jest.preset
に ts-jest
を設定しておきます。
これを設定しておかないと、import
構文などを理解できなくてエラーになります。
上記の jest
プロパティの値は、jest.config.js
という別ファイルとして定義することもできます。
これで、次のようにユニットテストを起動できます。
$ yarn test # yarn の場合
$ npm test # npm の場合
最初は何もテストコードがないので、実行しても次のようなエラーで終了するはずです(終了コード 1 はコマンドが失敗したことを表します)。
$ yarn -s test
No tests found, exiting with code 1
テストがないときにエラーにならないようにするには、--passWithNoTests
オプションを付けて実行します。
自動ビルド環境などで、常に yarn test
は実行しておきたい場合にお世話になるかもしれません。
$ yarn -s jest --passWithNoTests
No tests found, exiting with code 0
テストの記述
ここでは、次のような計算ライブラリをテスト対象のコードとして使うことにします。
Jest はデフォルトで次のようなファイルを検索してテストコードとして実行します。
- 拡張子が
.test.ts
(.test.js
) のファイル - 拡張子が
.spec.ts
(.spec.js
) のファイル __test__
ディレクトリ以下に配置した.ts
(.js
) ファイル
前述の計算ライブラリ (math.ts
) をテストするためのテストコードを、math.test.ts
というファイル名で作成します。
ファイル名のベース部分 (math
) はテスト対象のファイル名と合わせておくと分かりやすいでしょう。
テストコード内では、上記のように test(テスト名, テスト内容)
という形で各テストを定義します(test
の代わりに it
も使えます)。
計算結果の検証は、expect(実行結果).toBe(期待結果)
のように記述します。
次のようにテストを起動できます(yarn
の出力をシンプルにするために -s
オプションを指定しています)。
$ yarn -s test
PASS src/math.test.ts
√ add - positives (1 ms)
√ add - negatives
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 2.316 s, estimated 3 s
Ran all test suites.
すべてのテストが通りました!
さらに、--coverage
オプションを付けて実行することで、テストカバレッジのレポートを出力することができます。
テスト対象となったソースコードのうち何%がテストでカバーされているかを表示してくれます。
$ yarn -s test --coverage
PASS src/math.test.ts
√ add - positives (2 ms)
√ add - negatives (1 ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
math.ts | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 3.201 s
Ran all test suites.
Jest のマッチャー
expect(add(1, 2)).toBe(3)
上記の検証コードの toBe
の部分は マッチャー と呼ばれており、toBe
以外にも次のようなマッチャーが用意されています。
真偽値や null との比較
toBeTruthy()
… 値がtrue
であることを確認するtoBeFalthy()
… 値がfalse
であることを確認するtoBeNull()
… 値がnull
であることを確認するtoBeUndefined()
… 値がundefined
であることを確認するtoBeDefined()
… 値がundefined
でないことを確認する
test('null', () => {
const n = null
expect(n).toBeNull()
})
否定 (not)
not
を使うと、条件を反転できます。
expect(1).not.toBeNull()
数値の比較
数値の同値比較には toBe
あるいは toEqual
が使えますが、大小比較用のマッチャーも用意されています。
test('two plus two', () => {
const value = 2 + 2
expect(value).toBe(4)
expect(value).toBeGreaterThan(3)
expect(value).toBeGreaterThanOrEqual(3.5)
expect(value).toBeLessThan(5)
expect(value).toBeLessThanOrEqual(4.5)
})
浮動小数点数の同値比較には、toBe
ではなく toBeCloseTo
を使うようにします。
test('add floating point numbers', () => {
const value = 0.1 + 0.2
expect(value).toBeCloseTo(0.3) // Do not use 'toBe'
})
正規表現
文字列が正規表現に一致するかを調べるには、toMatch
を使用します。
次の例では、チーム名が team-
プレフィックスで始まっているかを調べています。
test('starts with "team-" prefix', () => {
const teamName = 'team-xxx'
expect(teamName).toMatch(/^team-/);
})
配列、セットのテスト
配列やセットの内容が等しいことを確認するには、toEqual
を使います。
toBe
を使うと参照の比較になってしまうので、toEqual
で実際の値を比較するようにします。
// 配列の比較
const arr = [1, 2, 3]
expect(arr).toEqual([1, 2, 3])
// セットの比較
const set = new Set([1, 2, 3])
expect(set).toEqual(new Set([1, 2, 3]))
配列やセットに特定の値が含まれているかどうかを調べるには、toContain
を使います。
test(`contain 200`, () => {
const arr = [100, 200, 300]
expect(arr).toContain(200)
})
指定した複数の値がすべて含まれているかどうかを調べるには、ちょっと複雑ですが、expect.arrayContaining
を組み合わせて次のようにします。
const arr = [1, 2, 3, 4, 5]
expect(arr).toEqual(expect.arrayContaining([3, 5, 1]))
例外のスロー
ある関数が例外を投げるかどうかを調べるには、toThrow
を使用します。
テスト対象の関数が expect
内で呼び出されるように、ラムダ式の形で渡すことに注意してください。
function foo() {
throw new Error()
}
test(`foo throws exeception`, () => {
expect(() => foo()).toThrow() // 何らかの例外をスローすることを確認
expect(() => foo()).toThrow(Error) // Error をスローすることを確認
})
その他のマッチャー
マッチャーの詳細は、expect API のページで確認することができます。
関連記事
- TypeScriptの型: 既存の型をちょっと変えた型を作る(ユーティリティ型)
- React コンポーネントで入力フォームを作成する (2) react-hook-form 編
- React の props.children の型定義には ReactNode を使う
- TypeScript で JSON オブジェクトに型情報を付加する
- TypeScript で undefined/null をうまく扱う (nullish coalescing (??), optional chaining (?.))
- TypeScript コードを Prettier で自動整形する
- DynamoDB を Node.js で操作する(SDK ver.2 の場合)