Chapter 05

JS ライブラリの単体テスト

Kei Touge
Kei Touge
2022.02.27に更新

🧪 テストを書こう

この my-hello-lib パッケージ は前章までで完成はしました。しかし、このライブラリに対してこれまで行なってきたような動作検証では不十分です。

なぜなら、それらの動作検証はこのパッケージが Hello. と出力するだけの単純なスクリプトだからこそ可能なものだったからです。今後、パッケージの規模が大きくなっていくとプログラムの定量的な品質保証をしてくれる自動化されたテストコードが必要となるでしょう。

単体テスト(ユニットテスト)とは?

単体テストとは、プログラムをモジュール(部品)ごとに分けて、そのモジュールごとが単体で正常に動作しているかを検証していくプロセスのことです。

たとえば、my-hello-lib ライブラリ をきちんと名前付きでインポートできるか、その hello() メソッド は正しく動作(Hello. をコンソールへ出力)するかということなどを検証していきます。

これらのテストを自動化してくれるのがテストフレームワークです。

https://qiita.com/yudwig/items/b85c27ac98bd9308e8da

本書では、いま最も人気があると言われているテストフレームワークの Jest を利用してテストを書いていきます。

https://jestjs.io/ja/

📥 Jest の導入

Jest のインストール

では、プロジェクトフォルダ直下へ戻り、jest とその関連パッケージをインストールしていきましょう。

zsh
% npm i -D jest ts-jest @types/jest @jest/types
  • jest: Jest の本体です。
  • ts-jest: TS で書かれたプロジェクトのテストに Jest を使えるようにします。
  • @types/jest: Jest の型定義ファイル。
  • @jest/types: jest.config を TS で書けるようにする型定義ファイル。

tsconfig.json のアップデート

tsconfig.json へ jest の型定義ファイルを追記します。

tsconfig.json
{
  "compilerOptions": {
    // 省略
    "types": ["node", "jest"],
    // 省略
  },
  "include": ["src"]
}

jest.config.ts の作成

プロジェクトフォルダ直下に jest の設定ファイル jest.config.ts を作成します。

jest.config.ts
// 型定義のインポート
import { Config } from '@jest/types';

// オプションを設定
const config: Config.InitialOptions = {
  preset: 'ts-jest',
  testMatch: ['<rootDir>/tests/**/*.test.ts'],
  testEnvironment: 'node',
  collectCoverage: true,
  errorOnDeprecated: true,
};

// 設定を default エクスポートします
export default config;

https://jestjs.io/ja/docs/configuration#オプション
  • preset: Jest の設定のベースとして使われるプリセットです。
  • testMatch: 今回は tests フォルダ内にテストファイルを置きます。
  • testEnvironment: node 環境 向けにテストします。
  • collectCoverage: カバレッジ(テストコードの捕捉率)を収集します。
  • errorOnDeprecated: 非推奨となった API を呼び出すとエラーメッセージを表示します。

package.json のアップデート

npm test で jest が実行されるように NPM スクリプトへ追記します。

package.json
    "test": "jest"

📝 テストを書く

プロジェクトフォルダ直下に tests ディレクトリを作成し、その中へ index.test.ts を配置します。

tests/index.test.ts
// 名前付きでインポートします
import { hello } from '../src';

describe('hello() のテスト', () => {
  it('Hello. と出力', () => {
    // コンソールのログ出力を監視し、その文字列を返します
    const log = jest.spyOn(console, 'log').mockReturnValue();

    // hello メソッドの実行
    hello();

    // 1番目のログ出力が 'Hello.' と一致するかチェック
    expect(log).toHaveBeenNthCalledWith(1, 'Hello.');

    // 'jest.spyOn()' によって作成されたモックをリセットします
    log.mockRestore();
  });
});

https://jestjs.io/ja/docs/mock-function-api

https://jestjs.io/ja/docs/expect

テストの実行

さっそくテストを実行しましょう。

zsh
% npm test

> my-hello-lib@1.0.0 test
> jest

 PASS  tests/index.test.ts
  hello() のテスト
    ✓ Hello. と出力 (2 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |
 index.ts |     100 |      100 |     100 |     100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.471 s
Ran all test suites.

テストをパスし、Uncovered Line に何も出力されていないのでカバレッジは 100% となったことが確認できます。

カバレッジの可視化

また、設定ファイルで collectCoverage: true としているので、以下のコマンドでカバレッジをブラウザでヴィジュアルにも確認できます。

zsh
% npx http-server -o coverage/lcov-report