Angularの単体テスト(ユニットテスト)をJestで行う方法

この記事では『Angularの単体テスト(ユニットテスト)』について

  • Jest・Jasmine・Karmaとは
  • Angularの単体テストをJestでする方法

などを分かりやすく説明するように心掛けています。ご参考になれば幸いです。

Jest・Jasmine・Karmaとは

Angularにはデフォルトで単体テスト(ユニットテスト)の環境が整っています。そのため、ng testコマンドやnpm run testコマンドを実行すると、単体テストが実行できるようになっています。

この単体テストには、Jasmine(ジャスミン)というテストフレームワークとKarma(カルマ)というテストランナーが使われています。このJasmineKarmaは必ずしもAngularのテストに必須のツールではありません。自由に他のツールを使用することができます。

ここで、この記事では、人気の高いテストフレームワークであるJestを用いて、Angularの単体テストを行う方法を説明します。

JestはFacebookが開発しているJavaScriptのテストフレームワークであり、ブラウザを起動してテストを実行するKarmaと比較すると、Jestはブラウザを起動する必要がなく、Node.js上でテストを実行するため、高速にテストを実行することが可能です。

また、Jestにはスナップショット機能モック機能など多くの便利な機能があります。スナップショット機能により、UIの変更を検出することができ、モック機能により、特定の関数の動作を制御したり、外部依存関係を模擬したりすることが可能です。

これらの特徴から、Jestは現在JavaScriptでは最も人気のあるテストフレームワークとなっています。

Angularの単体テストをJestで行う方法

Angularの単体テストをJestでする手順を以下に示します。

Angularの単体テストをJestでする手順

  • Jestで単体テストを実行する上で必要なパッケージをインストールする
  • 「jest-preset-angular」パッケージの「setup-jest」をインポートするファイルを作成する
  • Jestの設定ファイルを作成する
  • 「tsconfig.spec.json」ファイルを修正する
  • 「package.json」ファイルを修正する
  • テストに必要なファイルを用意する
  • テストを実行する
  • 不要になったパッケージやファイルを削除する

上記の手順について順番に説明します。

Jestで単体テストを実行する上で必要なパッケージをインストールする

カレントディレクトリ(現在作業しているディレクトリ)がプロジェクトのルートディレクトリであることを確認してください。その後、以下のコマンドを実行すると、Jestで単体テストを実行する上で必要なパッケージをインストールすることができます。

npm install --save-dev jest @types/jest jest-preset-angular

このコマンドにより、jest@types/jestjest-preset-angularが開発環境(devDependencies)として「package.json」ファイルに追加されます。

それぞれのパッケージについて

  • jest
    • Facebookが開発しているJavaScriptのテストフレームワークです。
  • @types/jest
    • Jestの型定義を提供しています。JavaScriptのライブラリをTypeScriptで使用する場合、ライブラリの型定義が必要になります。
    • @types/jestをインストールすることで、TypeScriptからJestのAPIを型安全に利用することが可能になります。
  • jest-preset-angular
    • AngularをJestでテストする際に必要な設定やスクリプトをあらかじめ定義したプリセットです。このプリセットを利用することで、Angularのテスト設定を簡単に行うことができます。

「jest-preset-angular」パッケージの「setup-jest」をインポートするファイルを作成する

プロジェクトのルートディレクトリに「setup-jest.ts」という名前のファイルを作成し、以下のような内容を記述します。

import 'jest-preset-angular/setup-jest';

「setup-jest.ts」ファイルはテストの実行前に読み込まれ、jest-preset-angularパッケージにおける特定の設定(この場合はsetup-jest)のみをインポートします。

ファイル名は任意です。ファイル名を変える場合、この後に作成する「Jestの設定ファイル(jest.config.js)」内の「パス(<rootDir>/setup-jest.ts')」の「setup-jest.ts」の箇所を「変更したファイル名」にしてください。

Jestの設定ファイルを作成する

プロジェクトのルートディレクトリに「jest.config.js」という名前のファイルを作成し、以下のような内容を記述します。

module.exports = {
  preset: 'jest-preset-angular',
  setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
};

<rootDir>/setupJest.tsというパスが指定されています。<rootDir>はプロジェクトのルートディレクトリを表します。また、「setup-jest.ts」は先ほど作成したファイル名と同じにします。

「tsconfig.spec.json」ファイルを修正する

Angular CLIの「ng new」コマンドで作成されたプロジェクトには、デフォルトで「tsconfig.spec.json」ファイルが作成されています。この「tsconfig.spec.json」ファイルを以下に示すように修正します。

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/spec",
    "types": [
      "jest"
    ]
  },
  "include": [
    "src/**/*.spec.ts",
    "src/**/*.d.ts"
  ]
}

「package.json」ファイルを修正する

「package.json」ファイルのscriptsセクションを更新して、npm testコマンドでJestが実行されるようにします。

{
  // その他のスクリプト
  "scripts": {
	// その他のスクリプト
    "test": "jest"
  },
 // その他のスクリプト
}

テストに必要なファイルを用意する

テストを行いたい「コンポーネントファイル」と「テストを行いたいコンポーネントのテストファイル」を用意します。以下に「AppComponent(app.component.ts)」と「テストファイル(app.component.spec.ts)」の一例を示します。

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `<h1>Hello, {{title}}</h1>`,
})
export class AppComponent {
  title = 'Angular!'
}

app.component.spec.ts

import { TestBed, ComponentFixture } from '@angular/core/testing';
import { AppComponent } from './app.component';

describe('AppComponent', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [AppComponent],
      providers: [],
      imports: []
    });
  });

  it(`titleプロパティに「Angular!」という文字列が格納されているか`, () => {
    const fixture: ComponentFixture<AppComponent> = TestBed.createComponent(AppComponent);
    const component: AppComponent = fixture.componentInstance;
    expect(component.title).toEqual('Angular!');
  });
});

あわせて読みたい

「AppComponent(app.component.ts)」と「テストファイル(app.component.spec.ts)」のコードについては以下の記事で詳しく説明しています。興味のある方は下記のリンクからぜひチェックをしてみてください。

テストを実行する

カレントディレクトリ(現在作業しているディレクトリ)がプロジェクトのルートディレクトリであることを確認してください。その後、以下のコマンドを実行すると、テストをすることができます。

npm test
# 以下のコマンドでもテストが可能です。
npm run test

実行結果

PS C:\Users\user01\Desktop\test\jestTest> npm test

> jest-test@0.0.0 test
> jest

 PASS  src/app/app.component.spec.ts
  AppComponent
    √ titleプロパティに「Angular!」という文字列が格納されているか (45 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.761 s, estimated 4 s
Ran all test suites.

Angularの単体テストをJestで実行することができました。

テスト実行時に警告が出た場合

テスト実行時に以下に示すような警告が出る場合があります。

ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.

上記の警告が表示された場合、以下に示すように、「tsconfig.spec.json」ファイルの"compilerOptions""esModuleInterop": true,を追加してください。

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/spec",
    "types": [
      "jest"
    ],
    "esModuleInterop": true,
  },
  "include": [
    "src/**/*.spec.ts",
    "src/**/*.d.ts"
  ]
}

【補足】テストを実行した時のバージョン

Angular CLI: 16.0.6
Node: 18.16.0
Package Manager: npm 9.6.6
OS: win32 x64

Angular: 16.1.2
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1601.1
@angular-devkit/build-angular   16.1.1
@angular-devkit/core            16.1.1
@angular-devkit/schematics      16.0.6
@angular/cli                    16.0.6
@schematics/angular             16.0.6
rxjs                            7.8.1
typescript                      5.0.4

【補足】今回利用しているjest関連のバージョン

"@types/jest": "^29.5.2",
"jest": "^29.5.0",
"jest-preset-angular": "^13.1.1",

不要になったパッケージやファイルを削除する

テストフレームワークをJestに切り替える際には、JasmineとKarmaに関するパッケージやファイルは不要になります。

JasmineとKarmaに関するパッケージやファイルを削除する方法をこれから説明します。

不要になったパッケージを削除する

Jestでテストを実行できることが確認できたので、JasmineとKarma関連のパッケージをアンインストールします。

npm uninstall @types/jasmine jasmine-core karma karma-chrome-launcher karma-coverage karma-jasmine karma-jasmine-html-reporter

Angular CLIの「ng new」コマンドで作成された「package.json」ファイルに記載されているJasmineとKarmaに関するパッケージを上記のコマンドではアンインストールしています。

不要になったファイルを削除する

不要になったJasmineとKarma関連のファイルを削除します。「karma.conf.js(Karmaの設定ファイル)」や「test.ts(Angularがテストを実行するために使用するファイル)」というファイルがプロジェクトディレクトリ内にある場合は削除しましょう。

「angular.json」ファイルからKarmaに関する設定を削除する

「angular.json」ファイル内のtestオプション内にあるbuilderフィールドを"@angular-devkit/build-angular:karma"から"@angular-builders/jest:run"に変更します。これにより、テストランナーがKarmaからJestに切り替わります。

{
  // その他のスクリプト
  "projects": {
    "jestTest": {
      // その他のスクリプト
      "architect": {
        "test": {
          "builder": "@angular-builders/jest:run",
          // その他のスクリプト
        }
      }
    }
  },
  // その他のスクリプト
}

必要に応じて他のKarmaに関連する設定があれば削除します。

【補足】最終的なディレクトリ構成

最終的なディレクトリ構成は以下のようになります(プロジェクトのルートディレクトリの名前がjestTestの場合)。

jestTest                        
├─src                           
│   ├─app                       
│   │   ├─app.module.ts 
│   │   ├─app.component.ts★          
│   │   └─app.component.spec.ts★      
│   ├─main.ts
│   ├─index.html
│   └─styles.css
├─angular.json★
├─jest.config.js★
├─package-lock.json
├─package.json★
├─setup-jest.ts★
├─tsconfig.app.json
├─tsconfig.json
├─tsconfig.spec.json★
└─node_modules

★マークの箇所が今回作成or編集したファイルです。

本記事のまとめ

この記事では『Angularの単体テスト(ユニットテスト)』について、以下の内容を説明しました。

  • Jest・Jasmine・Karmaとは
  • Angularの単体テストをJestでする方法

お読み頂きありがとうございました。