nyc (istanbul) でE2Eテストのカバレッジを取得する
E2Eテストや結合テストと呼ばれるような、GUIを用いて実システムの挙動を確認するテストはバックエンドのコードカバレッジが取れない。……と思い込んでいたのだが、ちょっと前に同僚から「E2Eテスト実行中に通ったコードと通ってないコードを測れば良いのでは」と言われ、目から鱗が落ちる思いだった。考えてみれば当たり前なのだが。
NodeJSでカバレッジを取るには nyc というコマンドラインツールを使うのが一般的なようだった。このツールは istanbul
というカバレッジ計測ツールを使うためのコマンドラインツールだ。
公式のものも含め、ググるとサンプルがたくさん出てくるのだが、どうもうまく行かず、解決に3日ほど費やした。最終的に nyc
の気持ちが何となく分かってきたので、備忘録も兼ねてまとめておく。
つまづいたポイント
基本的な使い方としては、 nyc
をインストールして、テスト実行時に nyc
を付けて実行すれば良い。以下は 公式 から取得したもの。
// package.json
{
"scripts": {
"test": "mocha",
"coverage": "nyc npm run test"
}
}
さて、今回はE2Eテストなので、Webアプリケーションの起動とテストコードの実行をそれぞれ叩く必要がある。例えば、以下のようなイメージである。
// package.json
{
"scripts" : {
"run": "node src/server.js",
"test": "mocha"
}
}
カバレッジを取りたいのは src
内にあるアプリケーションのコード群なので、 nyc
は run
側に付けることになる。
// package.json
{
"scripts" : {
"run": "nyc node src/server.js",
"test": "mocha"
}
}
ところが、これを実行したところ、カバレッジが全く取られなかった。
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 0 | 0 | 0 | 0 |
----------|---------|----------|---------|---------|-------------------
ググると、 all
オプションを付ける必要があるとのことだったで、 package.json
に付け足してみた。
// package.json
"nyc": {
"all": true,
"include": [
"src/**/*.js"
],
"reporter": [
"text",
"html"
]
},
すると、カバレッジには変化があったのだが、ほとんどの項目が0%になってしまう。少なくとも src/index.js
は絶対に通るはずなので、これはおかしい。
------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------------|---------|----------|---------|---------|-------------------
All files | 0 | 0 | 0 | 0 |
src | 0 | 0 | 0 | 0 |
index.js | 0 | 0 | 0 | 0 | 16-61
src/lib | 0 | 0 | 0 | 0 |
authConfig.js | 0 | 0 | 0 | 0 | 10-68
hashPassword.js | 0 | 100 | 0 | 0 | 4-7
src/routes | 0 | 0 | 0 | 0 |
items.js | 0 | 0 | 0 | 0 | 2-219
login.js | 0 | 0 | 0 | 0 | 2-28
order.js | 0 | 0 | 0 | 0 | 3-332
public.js | 0 | 100 | 0 | 0 | 5-10
signUp.js | 0 | 0 | 0 | 0 | 4-30
users.js | 0 | 0 | 0 | 0 | 2-18
------------------|---------|----------|---------|---------|-------------------
やったこと
StackOverflowの記事 によると、 nyc instrument
というコマンドを使う必要があるらしい。このコマンドは、元のソースコードにカバレッジ計測用のコードを付け足したものを出力してくれる。
例えば、以下のように実行すると、 src
内のコードをトランスパイルして .nyc_instrumented/server
に出力してくれる。
$ npx nyc instrument src ./.nyc_instrumented/server
アプリケーションを起動する際には、元の src/index.js
ではなく、 ./.nyc_instrumented/server/index.js
を実行する。この際も node
ではなく nyc node
のようにする必要がある。
// package.json
{
"scripts" : {
"run": "nyc node src/server.js",
"run:instrument": "nyc instrument src ./.nyc_instrumented/server && nyc node ./.nyc_instrumented/server.js",
"test": "mocha",
"report": "nyc report"
}
}
テスト実行は以下のような順序になる。
$ npm run run:instrument
$ npm run test
$ npm run report
すると、以下のようにカバレッジが出力される。
-------------------------------------------------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------------|---------|----------|---------|---------|--------------------------------------------------------------------
All files | 35.58 | 12.9 | 36.2 | 35.74 |
src | 92 | 50 | 100 | 92 |
index.js | 92 | 50 | 100 | 92 | 52-53
src/lib | 93.54 | 50 | 100 | 93.33 |
authConfig.js | 92.59 | 50 | 100 | 92.3 | 41,49
hashPassword.js | 100 | 100 | 100 | 100 |
src/routes | 20.37 | 5.76 | 21.27 | 20.67 |
items.js | 23.43 | 12.5 | 15.38 | 23.43 | 55-66,76-83,96-110,124-139,154-177,188-200,207-219
login.js | 70 | 50 | 75 | 70 | 6,27-28
order.js | 12.38 | 0 | 4.54 | 12.74 | ...176-178,183-188,197-266,274-290,298-302,309-316,320-324,328-332
public.js | 100 | 100 | 100 | 100 |
signUp.js | 18.75 | 0 | 33.33 | 18.75 | 7-10,14-30
users.js | 15.38 | 0 | 33.33 | 15.38 | 3-6,10-18
------------------|---------|----------|---------|---------|--------------------------------------------------------------------
おわりに
nyc
は複数のテストのカバレッジをマージできるらしいので、E2Eテストとユニットテストの結果をマージして全体でどの程度のカバレッジが出ているか算出できる。このカバレッジが100%になれば完璧というわけではなく、例えばフロントエンドとバックエンドとでデータフォーマットが違うみたいなケースには対応出来ないのだが、定量的なカバレッジのメトリクスとしては非常に役に立つと思う。他の言語でも似たような機能があると思うので(Railsとかにもあると聞いた)、時間があるときに試してみたい。
Discussion