javascriptまたはEcmaScript6(ES6)のプログラムの品質を保つ方法を、備忘録としてまとめてみたいと思います。
今回は第3回目です。istanbulというnpmパッケージを使って、プログラムが隈なくテストされているのかを計測したいと思います。これをテストカバレッジ(テストの網羅率)の取得 と呼んでいます。
前回は、javascriptやES6における、テストの書き方や使い方を簡単に解説していきました。期待した通りにプログラムが動作するか、テストコードで検証する事によって、プログラムの動作を隈なく検証することができます。
自身のブログjavascriptでプログラムのテストを行う方法を解説します。mocha・power-assertの簡単な使い方
私自身もテスト初心者ですので、できるだけ平たく説明していきます。もしこれは違う!という内容があればツッコミ をお待ちしております。
develop or drink ? photo by tea © 目次 javascriptで用いるモジュールをおさらい 第一回目 でも触れましたが、テストやテストカバレッジ取得を行うために、以下のnpmパッケージを使います。
mocha (モカ)
テストフレームワークと呼ばれているパッケージです。テストのプログラムを実行させることができる枠組みです。
power-assert (パワーアサート)
テストフレームワークのmochaに、想定した動作ルールを書くことができ、想定外のプログラム動作が見つかるとエラーで教えてくれます。この動作ルールのことをアサーション と呼んでいます。
intelli-espower-loader (なんて読むんだろ?)
power-assertを実行するために、コードを変換してくれるパッケージ。power-assertのテストを実行する際に、mochaの内部で利用します。
istanbul (イスタンブール)
テストのカバー率を調べることができます。プログラムにテストを行えていない箇所があれば、その箇所をエラーで教えてくれるため、テストを網羅するのに役立ちます。この網羅率の事をカバレッジ と呼んでいます。今回はistanbulの中でmochaのテストを実行し、同時にカバレッジも取得していく流れとなります。
今回は、上記のパッケージを使って、記述したjavascriptのプログラムのテストを行いつつ、テストのカバー率である「カバレッジ」を取得する方法について後述していきたいと思います。
パッケージのインストール それでは、必要なパッケージを用意していきたいと思います。これから書いていくコードは、前回のもの を利用し、一部は変更又は書き足していく形で進めていきたいと思います。もし前回をご覧になっていない方は、まずそちらをご覧いただくか、以下のサンプルコードをご確認ください。
サンプルコードサンプルコードはgithubにアップしていますので、そちらをご覧ください。
まずは、サンプルコードを実行するプロジェクトjs-test-practice
ディレクトリを作成し、npmパッケージをインストールします。
bash 1 2 3 4 5 $ git clone https://github.com/tea3/js-test-practice.git $ mkdir js-test-practice $ cd js-test-practice $ npm init $ npm install --save-dev istanbul mocha power-assert intelli-espower-loader
save-devオプションって何?npm install
コマンドの--save-dev
オプションは、開発で使うパッケージという意味合いを示すために指定しています。本体のプログラムでは使用せず、テストなど本体のプログラムで使わないパッケージがあれば、このオプションを指定してインストールしましょう。
また、node.jsやnpm、そしてコマンドラインについてご不明な場合は以下をご覧ください。
node.jsやコマンドラインについてnode.jsの環境を用意する方法やコマンドラインの使い方については以下を併せてご覧ください。
本体のプログラムを作成 続いて、プログラムの本体を書いて見たいと思います。
本体のプログラムは前回記事 の「外部ファイルの読み込みもテストで検証できる」の項目と同様の内容です。./index.js
と外部モジュール./lib/sample-lib.js
を作成して、挨拶のプログラムを用意したいと思います。
./index.js 1 2 3 4 5 6 const lib = require ('./lib/sample-lib.js' ) exports.hi = (name) => "やあ!" + name exports.hello = (name) => lib.hello(name) exports.helloSum = (name , ...arg) => `${lib.hello(name)} 。合計は${lib.sum(...arg)} です。`
./lib/sample-lib.js
は下記のようなコードになります。上記コード./index.js
で読み込んで利用します。
./lib/sample-lib.js 1 2 3 4 5 6 7 8 9 10 exports.hello = (name) => "はろー!" + name exports.sum = (...arg) => { let result = 0 for (let i of arg){ result += i } return result }
テストのプログラムを用意する それでは、先程用意した本体プログラムのメソッドhi(name)
とhello(name)
とhelloSum(name, ...arg)
の結果を検証するテストコード./test/test.js
を書いていきたいと思います。
こちらも前回記事 と同じ内容です。
./test/test.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 const assert = require ('power-assert' ) const myModule = require ('../index' ) describe('作ったプログラムを次の項目ごとにテストします' , () => { truedescribe('1. 挨拶のテスト その1' , () => { it('「こんにちは!」と挨拶しないとだめ' , () => { assert.equal(myModule.hi('太郎' ), 'こんにちは!太郎' ) }) }) describe('2. 挨拶のテスト その2' , () => { it('「はろー!」と挨拶しないとだめ' , () => { assert.equal(myModule.hello('太郎' ), 'はろー!太郎' ) }) }) describe('3. 挨拶と合計を計算するテスト' , () => { it('挨拶と合計を計算しないとだめ' , () => { assert.equal(myModule.helloSum('太郎' ,1 ,2 ,3 ), 'はろー!太郎。合計は6です。' ) }) }) })
次にpackage.json
を開き、scripts
の項目を以下のように変更します。
./package.json 1 2 3 4 5 6 7 8 9 { "name" : "test-practice" , "version" : "1.0.0" , "description" : "javascript test practice" , "main" : "index.js" , "scripts" : { "test" : "mocha test/test.js --require intelli-espower-loader" }, ...
それでは、上記で書いたテストを実行してみましょう。
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ npm run test > mocha test /test.js 作ったプログラムを次の項目ごとにテストします 1 . 挨拶のテスト その1 ✓ 「やあ!」と挨拶しないとだめ 2 . 挨拶のテスト その2 ✓ 「はろー!」と挨拶しないとだめ 3 . 挨拶と合計を計算するテスト ✓ 挨拶と合計を計算しないとだめ 3 passing (1 ms)
3 passing
と表示されれば、本体のプログラム./index.js
と外部モジュール./lib/sample-lib.js
に含まれる3つのメソッドが問題なく動作することが検証された事になります。
ここまでは前回と同様の結果です。
カバレッジを取得する ここからが本題です。先程行ったテストと併せて、テストの網羅率(=カバレッジ)を取得していきたいと思います。istanbulというパッケージを使いますので、インストールされていない場合には入れておきましょう。
bash 1 $ npm install --save-dev istanbul
次にpackage.json
を開き、scripts
の項目に、新しいコマンドtest-cov
を追記します。
./package.json 1 2 3 4 5 6 7 8 9 10 { "name" : "test-practice" , "version" : "1.0.0" , "description" : "javascript test practice" , "main" : "index.js" , "scripts" : { "test" : "mocha test/test.js --require intelli-espower-loader" , "test-cov" : "istanbul cover --print both _mocha -- test/test.js --require intelli-espower-loader" }, ...
上記のように、mochaのテストをistanbulから実行するようにtest-cov
というコマンドを用意します。それでは、test-cov
を実行してみましょう。
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 $ npm run test -cov > istanbul cover --print both _mocha -- test /test.js --require intelli-espower-loader 作ったプログラムを次の項目ごとにテストします 1 . 挨拶のテスト その1 ✓ 「やあ!」と挨拶しないとだめ 2 . 挨拶のテスト その2 ✓ 「はろー!」と挨拶しないとだめ 3 . 挨拶と合計を計算するテスト ✓ 挨拶と合計を計算しないとだめ 3 passing (1 ms) ============================================================================= Writing coverage object [/Users/**/js-test-practice/coverage/coverage.json] Writing coverage reports at [/Users/**/js-test-practice/coverage] ============================================================================= -----------------------|----------|----------|----------|----------|----------------| File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines | -----------------------|----------|----------|----------|----------|----------------| js-test-practice/ | 100 | 100 | 100 | 100 | | index.js | 100 | 100 | 100 | 100 | | js-test-practice/lib/ | 100 | 100 | 100 | 100 | | sample-lib.js | 100 | 100 | 100 | 100 | | -----------------------|----------|----------|----------|----------|----------------| All files | 100 | 100 | 100 | 100 | | -----------------------|----------|----------|----------|----------|----------------| =============================== Coverage summary =============================== Statements : 100 % ( 14 /14 ) Branches : 100 % ( 0 /0 ) Functions : 100 % ( 0 /0 ) Lines : 100 % ( 10 /10 ) ================================================================================
上記のように、テストの結果に続いて、カバレッジ取得の結果が出力されます。
全ての結果が100
と表示されれば、本体プログラムの./index.js
や./lib/sample-lib.js
が漏れなくテスト出来たことになります。
また、カバレッジの結果は./coverage
というディレクトリが作成され、./coverage/Icov-report/index.html
をブラウザで開くと、ブラウザからもカバレッジを確認する事ができます。
カバレッジレポートをブラウザで確認することができる ©
上記画像の中で、緑色で示されているコードは、テストによってカバーされている箇所を示しています。今回はテストのコードによって全てが網羅されていることが分かります。
テストが網羅できていないと、どうなるの? 先程は、カバレッジが100%の例を挙げました。それでは、テストの網羅が不完全だとどうなるのでしょうか?前回行ったテストの一部をコメントアウトして、再びカバレッジを取得してみましょう。
テストのコード./test/test.js
を下記のように、一部コメントアウトし、2つ目と3つ目のテストを無効にしてみましょう。
./test/test.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 const assert = require ('power-assert' ) const myModule = require ('../index' ) describe('作ったプログラムを次の項目ごとにテストします' , () => { describe('1. 挨拶のテスト その1' , () => { it('「こんにちは!」と挨拶しないとだめ' , () => { assert.equal(myModule.hi('太郎' ), 'こんにちは!太郎' ) }) }) })
それでは再びtest-cov
を実行してみましょう。
bash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 $ npm run test -cov > istanbul cover --print both _mocha -- test /test.js --require intelli-espower-loader 作ったプログラムを次の項目ごとにテストします 1 . 挨拶のテスト その1 ✓ 「やあ!」と挨拶しないとだめ 1 passing (1 ms) ============================================================================= Writing coverage object [/Users/**/js-test-practice/coverage/coverage.json] Writing coverage reports at [/Users/**/js-test-practice/coverage] ============================================================================= -----------------------|----------|----------|----------|----------|----------------| File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines | -----------------------|----------|----------|----------|----------|----------------| js-test-practice/ | 71.43 | 100 | 100 | 100 | | index.js | 71.43 | 100 | 100 | 100 | | js-test-practice/lib/ | 28.57 | 100 | 100 | 33.33 | | sample-lib.js | 28.57 | 100 | 100 | 33.33 | 3 ,4 ,5 ,7 | -----------------------|----------|----------|----------|----------|----------------| All files | 50 | 100 | 100 | 60 | | -----------------------|----------|----------|----------|----------|----------------| =============================== Coverage summary =============================== Statements : 50 % ( 7 /14 ) Branches : 100 % ( 0 /0 ) Functions : 100 % ( 0 /0 ) Lines : 60 % ( 6 /10 ) ================================================================================
上記の結果は、テストは1つ実行され、問題なく通っています。ただし、テストカバレッジはStatements 50%
となっており、まだテストされていない箇所があることを示しています。
生成されたカバレッジレポート(./coverage/Icov-report/index.html
)をブラウザで開いてみましょう。
上記画像を見ると、赤く示された箇所のプログラムがテストされていない事がわかります。赤い箇所は、先程コメントアウトしたテストコードと一致しています。
実際のプログラムでは、メインプログラムの極力広い範囲がカバーされるように、テストのコードを書いていく事になります。
まとめ という事で、今回はjavascriptやES6における、テストの網羅率(=カバレッジ)を取得する方法を分かりやすくまとめました。
npmパッケージのistanbulを使うと、プログラムが期待通りに動作するのか否かや、また同時に、テストコードがメインプログラムの動作を隈なく検証することができたのかを機械的に計測することができます。
次回は、ESLintを使って、JavascriptやES6のコーディングをチェックする方法について解説していきます。
自身のブログjavascriptで構文をチェックする方法を解説します。ESLintの簡単な使い方