Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
AngularJS TIPS

AngularJS TIPS

AngularJSアプリの単体テストを実施するには?(実行編)

2016年8月24日

テスティングフレームワーク「Karma+Jasmin」を使って、AngularJSアプリの単体テストを記述して、それをテスト実行するまでの手順を説明する。

  • このエントリーをはてなブックマークに追加

 別稿1「TIPS:AngularJSアプリの単体テストを実施するには?(準備編)」では、AngularJSアプリの単体テストを実施するための環境として、KarmaJasmineをインストールする手順を紹介しました。本稿では、この環境を利用して、具体的なテストコードを書いて、実際にテストを実行するまでを解説します。

(1)テスト対象のコード

 テスト対象のコードには、別稿2「TIPS:フィルターを自作するには?」で紹介した自作のtrimフィルターを採用します。別稿2ではtrim.htmlファイルを作成していますが、本稿で説明するテスト用に、/angular_tips/UnitTest/scriptsフォルダー内にtrim.jsファイルを新規作成し、別稿2のtrim.htmlファイルで示しているJavaScriptコード部分のみをtrim.jsファイルにコピーしてください。具体的にはリスト1のようになります(コードの詳細は別稿2を参照してください)。なお、今後のTIPSで使い分けるために、今回のサンプルコードではモジュール名を「myApp」から「myApp.filter」に変更しているので注意してください。

JavaScript
angular.module('myApp.filter', [])
  // trimフィルターを定義
  .filter('trim', function() {
    return function(value) {
      // 加工対象の値が文字列であるかを判定
      if (!angular.isString(value)) {
        return value;
      }
      // 文字列の前後から空白を除去
      return value.trim();
    };
  })
  .controller('MyController', ['$scope', function($scope) {
    $scope.msg = '   こんにちは、世界!   ';
  }]);
リスト1 テスト対象となるtrimフィルターのコード(/angular_tips/UnitTest/scripts/trim.js)
(2)テストスクリプトを準備する

 まずは、テストのためのコードを準備します。テストスクリプト(リスト2)は、Karmaの初期化ファイルkarma.conf.jsfilesパラメーターで指定したフォルダー(本連載では/spec)に「~_spec.js」のような名前で保存してください。

JavaScript
1
2
 
3
 
 
 
 
 
 
 
describe('trimフィルターのテスト', function() {
  beforeEach(module('myApp.filter'));
 
  it('文字列の前後から空白を除去', inject(function($filter) {
    var msg = '   こんにちは、世界!   '; // 引数
    var result = 'こんにちは、世界!';  // 期待される結果
    // trimフィルターを実行して、結果を検証
    var trim = $filter('trim');
    expect(trim(msg)).toEqual(result);
  }));
});
リスト2 trimフィルターをテストするためのコード(/angular_tips/UnitTest/spec/trim_spec.js)

 Jasmineでテストスクリプトを記述する場合の基本的な構文を押さえておきます。

 まず、テストスクリプト全体を、describeメソッドでくくります(1)。

[構文]describeメソッド

describe(name, specs)

  • name: テストスイートの名前
  • specs: テストケースの集合

 テストスイートとは、関連するテストをまとめた入れ物のようなものです。具体的な個々のテストケースは、引数specs(function型)の配下で定義します。

 beforeEachメソッドは、個々のテストを実施する前に呼び出される初期化処理です(2)。ここでは、module関数を利用して、テスト対象となるtrimフィルターが属するmyApp.filterモジュールを登録しておきます。AngularJS標準のngモジュールや、モック(後日解説)を提供するngMockモジュールは自動的に有効になりますので、明示的に登録する必要はありません。

 ここでは省略していますが、テストの終了処理にはafterEachメソッドも利用できます。

 そして、個々のテストケースを表すのが3itメソッドです。ここでは、1つだけテストケースを用意していますが、複数のテストケース(itメソッド)を列記することも可能です。

[構文]itメソッド

it(name, test)

  • name: テストケースの名前
  • test: テストの中身

 引数test(function型)にAngularJSのサービスを注入するには、inject関数を利用します。inject関数を利用することで、引数と同名のサービスを注入できます(この挙動については、別稿3「TIPS:AngularJSの依存性注入を利用するには?」でも解説しています)。

 あとは$filterメソッドtrimサービスを呼び出し、その結果を以下の構文で検証するだけです。

[構文]コードの結果を検証

expect(test_code).matcher(expect)

  • test_code: テスト対象のコード(式)
  • matcher: 検証メソッド
  • expect: 期待する値

 この例であれば、trim(msg)trimフィルターを実行し、(toEqualメソッドにより)その結果が変数resultの値と等しいことを確認しています。

 toEqual検証メソッドアサーションメソッド、あるいはMatcherとも呼ばれ、結果確認のための機能を提供するメソッドの一種です。Jasmineでは、標準で以下のような検証メソッドを用意していますので、時と場合とで使い分けてください。

メソッド 概要
toEqual(expect) 期待値expectと同じ値か
toBe(expect) 期待値expectと同じオブジェクトか
toMatch(regex) 正規表現regexにマッチするか
toBeDefined() 定義済みか
toBeNull() null
toBeTruthy() trueと見なせる値か
toBeFalsy() falseと見なせる値か
toContain(expect) 期待値expectが配列に含まれているか
toBeLessThan(compare) 比較値compareより小さいか
toBeGreaterThan(compare) 比較値compareより大きいか
toBeCloseTo(compare, precision) 精度precisionに丸めた値が比較値compareと同じか
toThrow() 例外が発生するか
Jasmine標準の検証メソッド

 否定を表すならば、notメソッドを併用してください。例えば、以下は「等しくない」ことを確認するためのコードです。

JavaScript
expect(trim(msg)).not.toEqual(result));
リスト3 notメソッドを使って否定を表現しているテストコード
(3)テストスイートを実行する

 準備したテストを実行するには、karma startコマンドを実行してください。引数には、準備済みの設定ファイルkarma.conf.jsを指定します。

コンソール
> karma start karma.conf.js
……中略……
Chrome 51.0.2704 (Windows 10 0.0.0): Executed 1 of 1 SUCCESS (0.035 secs / 0.028 secs)
リスト4 Karmaでテストスクリプトを実行
図1 JasmineがChromeを自動的に起動し、テストを実行する

 テスト環境(本稿では別項1でkarma initコマンド実行時に指定したChrome)が起動し、テストを実行します。テスト実行可能な状態では図1のように[connected]と表示され、実行中には実行状況も表示されます。

 テストの結果はコマンドプロンプト(Windows)/ターミナル(Mac)から確認できます。リスト4の最終行を見ると、1つのテストが1つ成功(SUCCESS)したことが見て取れます。

 試しに、先ほどのテストスクリプトを、あえてテストが失敗するように修正してみましょう。

JavaScript
expect(trim(msg)).not.toEqual(result));
リスト5 テストを失敗するように修正したコード(trim_spec.js)

 別稿1で作成したkarma.conf.jsではautoWatch: trueとコードの変更を検知して、テストを再実行する設定になっています。このため、trim_spec.jsファイルを保存したところでテストが実行され、コマンドプロンプトに以下の結果が反映されるはずです。

コンソール
Chrome 51.0.2704 (Windows 10 0.0.0) trimフィルターのテスト 文字列の前後から空白を除去 FAILED
Expected 'こんにちは、世界!' not to equal 'こんにちは、世界!'.
  at Object.<anonymous> (spec/trim_spec.js:8:27)
  at Object.invoke (lib/angular.js:4709:19)
  at Object.workFn (lib/angular-mocks.js:3109:20)
Chrome 51.0.2704 (Windows 10 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.05 secs / 0.036 secs)
リスト6 テストが失敗(FAILED)した場合の結果
処理対象:テスト カテゴリ:基本
処理対象:Karma+Jasmine カテゴリ:基本
処理対象:フィルタリング カテゴリ:基本
処理対象:カスタムフィルター カテゴリ:基本
API:angular.module カテゴリ:ng(コアモジュール) > function(関数)
API:$injector カテゴリ:auto > service(サービス)

※以下では、本稿の前後を合わせて5回分(第67回~第71回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

AngularJS TIPS
67. パラメーター付きのサービスを定義するには?(providerメソッド)

value/service/factoryメソッドに比べてより原始的なproviderメソッドの利用場面を紹介し、使い分け指針をまとめる。またproviderメソッドを使ってサービスを定義する方法を解説する。

AngularJS TIPS
68. AngularJSアプリの単体テストを実施するには?(準備編)

AngularJSで一般的に採用されているテスティングフレームワーク「Karma+Jasmin」による単体テスト環境を構築する手順を説明する。

AngularJS TIPS
69. 【現在、表示中】≫ AngularJSアプリの単体テストを実施するには?(実行編)

テスティングフレームワーク「Karma+Jasmin」を使って、AngularJSアプリの単体テストを記述して、それをテスト実行するまでの手順を説明する。

AngularJS TIPS
70. AngularJSのサービスを単体テストするには?

テスティングフレームワーク「Karma+Jasmin」を使って、AngularJSの「サービス」の単体テストを記述し、それを実行する方法を解説する。

AngularJS TIPS
71. AngularJSのコントローラーを単体テストするには?

テスティングフレームワーク「Karma+Jasmin」を使って、AngularJSの「コントローラー」の単体テストを記述し、それを実行する方法を解説する。

サイトからのお知らせ

Twitterでつぶやこう!