Karma+istanbulを利用して、AngularJSで構築したプロダクトのCoverage計測

Advent Calendarを通じて、公式ページの各種情報を参考に文章化したことと他の方々の投稿を読み進めることによって、AngularJSの基本的なところを大分理解できてきました。改めて、テストを通して開発できるAngularの良いところやUJSに沿った形の仕組みを構築でき、無理なくHTMLページをリッチにできる仕組みであることを感じてきています。

当初から、Angularのテストを手軽に行えるところが良いという理由を散々述べてきました。
今回、さらに、テストについて踏み込んだ記事として、若干Angularから離れますが、コードカバレッジの計測方法を取りまとめます。

Angularのようにテストを書き易いフレームワークを導入したとして、製造フェーズをテストファーストにして、テストコードを書いてプロダクトの品質をある程度担保できたとしても、結局、テストコードを書くのは人です。場合によっては、テストコードに問題や抜けが発生することはどうしようもないことです。
テストコードが意味のない存在にしないように、テストコードの保守が欠かせません。

意味がない状況になることを未然に防いだり、テストコードの保守を行いやすいようにする方法の一つとして、テストのプロダクトコードに対する網羅性を確認する手段が、一般的なTDDのテストランナーには準備されています。そして、運の良いことに、このコードカバレッジを計測する手段はKarmaにも用意されています。

プロダクトコードに対するテストのコードカバレッジを計測する仕組みは、プロジェクト開始当初から導入しておくに超したことのない仕組みです。品質向上のためのテストをメンテナンスする際に必ず生きてくる仕組みだからです。

[A post-mortem on my first AngularJS project : JohnMunsch.com](http://johnmunsch.com/2013/09/22/a-post-mortem-on-my-first-angularjs-project/)
http://johnmunsch.com/2013/09/22/a-post-mortem-on-my-first-angularjs-project/

上記の記事がシンプルでわかりやすく手順が記述されていましたので、参考にして、Angularの[Tutorial](http://docs.angularjs.org/tutorial/)の[step-5](http://docs.angularjs.org/tutorial/step_05)に対してカバレッジ計測を行った手順とその結果をレポートします。

### 1． Karma のインストール

Angularの[Tutorial](http://docs.angularjs.org/tutorial/2)をやっている場合は不要ですが、下記を実行してKarmaをインストール

```
npm install -g karma
```

### 2. カバレッジ計測用のモジュールをインストール

istanbulをインストールするのではなく、karma-coverageというモジュールをインストールします。
istanbul含むカバレッジ計測で必要なモジュール群がインストールされます。

```
npm install karma-coverage --save-dev
```

### 3. angular-mocks.jsをインストール

こちらも[Tutorial](http://docs.angularjs.org/tutorial/)を進めている場合には不要です。app/lib/angular-mocks.jsがありますので。
bowerのインストールに関しては、gitにPATHの通っている環境で実行する必要があります。
(手元でやった時は、SourceTreeから起動できるTerminal上で実行しました)

```
npm install bower
bower install angular-mocks --save-dev
```
GruntとかYoemonなど便利なものがありますが、まだ勉強中なのでひとまず素でインストールしました。

### 4． karma.conf.jsを再作成

[Tutorial](http://docs.angularjs.org/tutorial/)の[step-5](http://docs.angularjs.org/tutorial/step_05)の「config/karma.conf.js」をそのまま利用するとうまくいかないので、下記の手順でひと通り作成します。

```
karma init
```
configファイルを作成するために、いくつかの質問を聞かれるので、実行した環境に合わせて設定してください。
作成されたconfigファイルのサンプルは下記の通りです。

```ｊｓ:karma.conf.js
// Karma configuration
// Generated on Wed Dec 18 2013 03:00:59 GMT+0900 (譚ｱ莠ｬ (讓呎ｺ匁凾))

module.exports = function(config) {
  config.set({

    // base path, that will be used to resolve files and exclude
    basePath: '',


    // frameworks to use
    frameworks: ['jasmine'],

    // list of files / patterns to load in the browser
    files: [
      'app/lib/angular/angular.js',
      'app/lib/angular/angular-*.js',
      'bower_components/angular-mocks/angular-mocks.js',
      'app/js/*.js',
      'test/unit/*Spec.js',
    ],

    // list of files to exclude
    exclude: [
    'app/lib/angular/angular-scenario.js'
    ],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // Start these browsers, currently available:
    // - Chrome
    // - ChromeCanary
    // - Firefox
    // - Opera (has to be installed with `npm install karma-opera-launcher`)
    // - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`)
    // - PhantomJS
    // - IE (only Windows; has to be installed with `npm install karma-ie-launcher`)
    browsers: ['Chrome'],

    // If browser does not capture in given timeout [ms], kill it
    captureTimeout: 60000,

    preprocessors: { 'app/js/**/*.js': 'coverage' },
    // test results reporter to use
    // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
    reporters: ['progress', 'coverage'],

    // Continuous Integration mode
    // if true, it capture browsers, run tests and exit
    singleRun: false
  });
};
```
この設定でポイントは、filesディレクティブのところは、UnitTestだけを対象にしたconfig/karma.conf.jsを参考にしている点です。e2eのテスト含めると当然ながらテスト方法がことなるため、こけます。
また、confg/karma.conf.jsにはpluginsディレクティブがありますが、それを移設すると「coverageモジュールが登録されていない!」と怒られるので不要です。

### 3． coverageレポートを出力するディレクトリを作成

カバレッジ計測結果のレポートは、appディレクトリと同じ階層に設置します。

### 4． karmaを起動

下記のコマンドでkarmaを起動します。

```
karma init
```
これで、エラーが発生していなければ、ブラウザが立ち上がった後に、coverageディレクトリを覗くといくつかのディレクトリとファイルが作られているはずです。手元の環境では、下記のファイル群が出力されました。

```
$ ls coverage　| cat
Chrome 31.0.1650 (Windows Vista)
coverage-Chrome 31.0.1650 (Windows Vista)-20131218_032855.json
```
上記のjsonファイルじゃない方のディレクトリの中にHTMLファイルが作成されています。
ブラウザでファイルを開くとカバレッジ計測の結果を閲覧できます。

ちなみに[Tutorial](http://docs.angularjs.org/tutorial/)の[step-5](http://docs.angularjs.org/tutorial/step_05)のcheckout直後の場合、テストがオールグリーンにはならないため、下記の結果になります。

![テスト失敗時.png](https://qiita-image-store.s3.amazonaws.com/0/6846/b6e68ffa-9752-4442-943f-0a3977c0878f.png)

そして、修正後は下記の結果になります。

![テスト成功時.png](https://qiita-image-store.s3.amazonaws.com/0/6846/ca32b9c0-66ea-c1b3-51bf-a0752f293d45.png)

不思議と、オールグリーンの状態を見るとホッとしてそれまでの疲れも何故かちょっと和らぎます（緑や安らぎの色合いですし)。
PC相手にストレスの溜まっていく職業なので、精神衛生上、テストを作成して、カバレッジ計測して、オールグリーン状態にする文化は重要だと思います。

以上のとおり、AngularとKarma+istanbulを組み合わせてカバレッジ計測の方法をレポートしました。


その他参考:
[Angular.js code coverage using Karma w. Coffeescript](http://stackoverflow.com/questions/16582633/angular-js-code-coverage-using-karma-w-coffeescript)
http://stackoverflow.com/questions/16582633/angular-js-code-coverage-using-karma-w-coffeescript

[JSのカバレッジ計測](https://github.com/yahoo/istanbul)
https://github.com/yahoo/istanbul