grunt-istanbulを使ってテストカバレッジを出力する

JSのテストカバレッジの生成ツールとして、[istanbul](https://github.com/gotwarlost/istanbul)というのがあるけれど
それをGruntタスクに取り込むための方法。

具体的には、mochaを使って、[grunt-istanbul](https://github.com/taichi/grunt-istanbul)を使えるようにする流れ。

例は https://github.com/hiroosak/grunt-istanbul-example に記載してます。

# 処理の流れ

カバレッジを出力するには

1. アプリコードをカバレッジ用コードに変換する
2. カバレッジ用のコードに対してテストを実行する
3. カバレッジの結果を保存する
4. カバレッジレポートを出力する

それぞれで、gruntの別タスクで処理が行われる。

1. `instrument`タスク
2. `mochaTest` タスク
3. `storeCoverage` タスク
4. `makeReport` タスク

## instrument タスク

カバレッジの生成タスクの名前は `instrument`。

設定の仕方は以下のような感じ。

```js:Gruntfile.js
  grunt.initConfig({
    // ...
    instrument: {
      files: 'app/**/*.js',
      options: {
        lazy: true,
        basePath: 'test/coverage/instrument/'
      }
    },
    // ...
  });
```

上ではコピー先とコピー元を決定している。
環境のディレクトリ構成を気にして設定する必要がある。

```bash
.
├── Gruntfile.js
├── app/                # ここ以下のファイルを変換して ↓
│   ├── routes/
│   └── views/
# 省略...
└── test/
    ├── coverage/
    │   ├── instrument
    │   │   └── app     # ここに持ってくる
    │   │        └── routes
    │   └── reports
    ├── require_helper.js
    └── router.test.js
```

## mocha タスク

mochaタスクは通常の [grunt-mocha-cli](https://github.com/Rowno/grunt-mocha-cli) と同様。

ただし、カバレッジを取る場合は、`test/coverage/instrument/app`以下を読み込む。ただ、カバレッジを取りたくない時は `app/`以下のコードを利用したい。

なので、`require_helper.js`を用意して、環境変数で読み込みのappを変更できるようにする。

```js:test/require_helper.js
'use strict';

module.exports = function (path) {
  return require((process.env.APP_DIR_FOR_CODE_COVERAGE || '../app/') + path);
};
```

なので、`test/router.test.js` は `app/`以下のrequireを行う場合に、`require_helper`をはさんで、読み込みをしている。

```js:test/router.test.js
var requireHelper = require('./require_helper');
var router = requireHelper('routes/');
```

また、`APP_DIR_FOR_CODE_COVERAGE` は `Gruntfile.js` 内で [grunt-env](https://github.com/jsoverson/grunt-env)を使って設定を行う。

```js:Gruntfile.js
    env: {
      coverage: {
        APP_DIR_FOR_CODE_COVERAGE: '../test/coverage/instrument/app/'
      }
    },
```

## storeCoverage タスク

```js:Gruntfile.js
    storeCoverage: {
      options: {
        dir: 'test/coverage/reports'
      }
    },
```

## makeReport タスク

```js:Gruntfile.js
    makeReport: {
      src: 'test/coverage/reports/**/*.json',
      options: {
        type: 'lcov',
        dir: 'test/coverage/reports',
        print: 'detail'
      }
    }
```

## タスクの設定

必要なnpmのロードと、タスクの設定。

```
  // plugins
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-mocha-test');
  grunt.loadNpmTasks('grunt-istanbul');
  grunt.loadNpmTasks('grunt-env');

  // tasks
  grunt.registerTask('test', ['mochaTest']);
  grunt.registerTask('coverage', ['clean', 'instrument', 'env:coverage', 'mochaTest', 'storeCoverage', 'makeReport']);
```

`grunt test` なら `mochaTest` を実行する。

`grunt convert` なら カバレッジ出力を行うために必要な設定をしながら、`mochaTest` を実行すれば、以下のようにカバレッジの結果が表示される。

![Screen Shot 0026-06-14 at 11.54.48 PM.png](https://qiita-image-store.s3.amazonaws.com/0/3163/e68e4282-ea48-2de5-44cd-84a57ed4b133.png)

# まとめ

[grunt-istanbul](https://github.com/taichi/grunt-istanbul)でカバレッジを取るためには、一度テストターゲットを変換する必要があるために、ディレクトリ構成に気をつかう必要がある。
さもなければ、[grunt-contrib-copy](https://github.com/gruntjs/grunt-contrib-copy)を使って、instrumentの置き場所に、色々構成を入れなければいけなくなるので注意が必要。

また、すでにテストコードがあるものから使う場合に、テストコードに修正を加える必要がある可能性がある。

サンプルは [hiroosak/grunt-istanbul-example](https://github.com/hiroosak/grunt-istanbul-example) に。