javascriptまたはEcmaScript6(ES6)のプログラムの品質を保つ方法を、備忘録としてまとめてみたいと思います。
今回は第二回目です。mocha、power-assertを使って、プログラム動作が期待通り書かれているのか検証を行う方法について分かりやすく解説していきたいと思います。
なお前回は、javascriptやES6におけるテスト環境についての概要や、テストの必要性について簡単に触れました。
私自身もテスト初心者ですので、できるだけ平たく説明していきますが、もしこれは違う!という内容があればツッコミをお待ちしております。
目次
javascriptで用いるモジュールをおさらい
前回も触れましたが、テストを行うために、以下のnpmパッケージを使います。
mocha (モカ)
テストフレームワークと呼ばれているパッケージです。テストのプログラムを実行させることができる枠組みです。
power-assert (パワーアサート)
テストフレームワークのmochaに、想定した動作ルールを書くことができ、想定外のプログラム動作が見つかるとエラーで教えてくれます。この動作ルールのことをアサーションと呼んでいます。
intelli-espower-loader (なんて読むんだろ?)
power-assertを実行するために、コードを変換してくれるパッケージ。power-assertのテストを実行する際に内部で利用します。
今回は、上記のパッケージを使って、記述したjavascriptのプログラムが想定した動作を行っているのか?を調べてみたいと思います。
プロジェクトを作成し、パッケージのインストール
それでは、具体的に本体のプログラムや、テストプログラムを書いていきたいと思います。まずはjavascriptのプロジェクト(例:js-test-practice
ディレクトリ)を作成し、そのディレクトリでnpmパッケージをインストールします。
bash1 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 mocha power-assert intelli-espower-loader
|
npmでインストールするパッケージは前項で紹介したmocha、power-assert、intelli-espower-loaderです。
save-devオプションって何?
npm install
コマンドの--save-dev
オプションは、開発で使うパッケージという意味合いを示すために指定しています。本体のプログラムでは使用せず、テストなど本体のプログラムで使わないパッケージがあれば、このオプションを指定してインストールしましょう。
また、node.jsやnpm、そしてコマンドラインについてご不明な場合は以下をご覧ください。
node.jsやコマンドラインについて
node.jsの環境を用意する方法やコマンドラインの使い方については以下を併せてご覧ください。
本体のプログラムを作成
続いて、プログラムの本体を書いて見たいと思います。
サンプルコード
サンプルコードはgithubにアップしていますので、そちらをご覧ください。
./index.js
を新規作成します。動作内容は下記のように引数へ名前を渡すと、挨拶の言葉を返すような関数を書いてみたいと思います。
./index.js1 2
| exports.hi = (name) => "やあ!"+ name
|
上記のhi(名前)
というメソッドは、やあ!名前
という結果を返す関数でなくてはなりません。今回はこの仕様をテストで検証してみたいと思います。
テストコードを作成
続いて、テストを書いてみたいと思います。テストは先程作成した./index.js
の動作が想定した仕様通りに動作するのかを検証できるように記述していきます。
それでは、./test/test.js
を新規作成し、次のようなコードを記述してみましょう。
./test/test.js1 2 3 4 5 6 7 8 9 10 11 12
| const assert = require('power-assert') const myModule = require('../index')
describe('作ったプログラムを次の項目ごとにテストします' , () => { truedescribe('1. 挨拶のテスト その1', () => { it('「やあ!」と挨拶しないとだめ', () => { assert.equal(myModule.hi('太郎'), 'やあ!太郎') }) }) })
|
テストでは、上記のようにdescribe
というテストの説明が書ける関数の中で、いくつかのテストコードをit()
の中で記述していきます。
テストコードの中を詳しく見ていきたいと思います。it()
の中では、assert.equal()
によって、index.js
のプログラムが想定した結果を返すのかが検証されています。上記の例では、myModule.hi('太郎')
の結果が'やあ!太郎'
となればテストは正常クリアされた事になります。
テストを実行してみる
それでは、上記で書いたmocha、power-assertのテストコードを実行して、本体プログラムのindex.js
が想定通りに動作しているのかチェックしてみましょう。
まず、$ npm init
コマンドで作成されたpackage.json
を開き、scripts
の項目を以下のように変更します。
./package.json1 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" }, ...
|
上記の記述によって、$ npm run test
というコマンドから、テスト実行コマンドのmocha test/test.js
が実行できるようになります。また、テストコマンドでは、前半でご紹介したintelli-espower-loader
というパッケージを内部で使用する事によってテスト用のコードに変換してくれます。
bash1 2 3 4 5 6 7 8 9 10 11 12
| $ npm run test-normal
> mocha test/test.js
作ったプログラムを次の項目ごとにテストします 1. 挨拶のテスト その1 ✓ 「やあ!」と挨拶しないとだめ
1 passing (1ms)
|
上記のように、1 passing
と表示されれば、テストが期待した結果通りに動作したことを検証できた事になります。このように、テストコードで書いたdescribe
の概要コメントが表示され、テストが通ったか否かを感覚的に把握できるのが、power-assert
などのアサーション・ライブラリと呼ばれるパッケージの特徴となっています。
テストに失敗すると、どうなるの?
前述のサンプルでは、テストに問題なくパスすることができました。しかし、テストに失敗するとどうるのでしょうか?試しに誤ったテストを書いてみましょう。
./test/test.js1 2 3 4 5 6 7 8 9 10 11 12
| const assert = require('power-assert') const myModule = require('../index')
describe('作ったプログラムを次の項目ごとにテストします' , () => { truedescribe('1. 挨拶のテスト その1', () => { it('「こんにちは!」と挨拶しないとだめ', () => { assert.equal(myModule.hi('太郎'), 'こんにちは!太郎') }) }) })
|
上記のテストコードでは、本体プログラムでは返さない結果「こんにちは!(名前)」を返すよう変更しました。それでは、テストコードを実行してみましょう。
bash1 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
| $ npm run test-normal
> mocha test/test.js
作ったプログラムを次の項目ごとにテストします 1. 挨拶のテスト その1 1) 「こんにちは!」と挨拶しないとだめ
0 passing (1ms) 1 failing
1) 作ったプログラムを次の項目ごとにテストします 1. 挨拶のテスト その1 「こんにちは!」と挨拶しないとだめ:
AssertionError [ERR_ASSERTION]: assert.equal(myModule.hi('太郎'), 'こんにちは!太郎') | | | "やあ!太郎" Object{hi: + expected - actual
-やあ!太郎 +こんにちは!太郎
|
上記のように、0 passing 1 failing
と表示されると、テストは失敗という事になります。テストが失敗すると-やあ!太郎 +こんにちは!太郎
のように、本体プログラムとテストコードで書いた想定値の食い違いを、直感的に把握することができます。
実際のテストでは、期待通りにプログラムが動作するようにテストを実行し、テストが失敗すればその箇所をデバッグするという流れになっていきます。
外部ファイルの読み込みもテストで検証できる
node.jsでは、外部ファイルに関数を分けて記述することも多々あるかと思います。テストでは、ファイルが幾つかに別れているケースも検証することができます。
それでは、試しに外部モジュール./lib/sample-lib.js
を作成し、以下のような関数を書いてみましょう。
./lib/sample-lib.js1 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 }
|
続いて上記で作成した./lib/sample-lib.js
を./index.js
で読み込み、関数を使用します。
./index.js1 2 3 4 5 6 7 8
| 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)}です。`
|
それでは、新たに追加したメソッドhello(name)
とhelloSum(name, ...arg)
の結果を検証するテストコードを2つ書いていきたいと思います。
./test/test.js1 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です。') }) })
})
|
上記で書いたテストを実行してみましょう。
bash1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| $ npm run test-normal
> mocha test/test.js
作ったプログラムを次の項目ごとにテストします 1. 挨拶のテスト その1 ✓ 「やあ!」と挨拶しないとだめ 2. 挨拶のテスト その2 ✓ 「はろー!」と挨拶しないとだめ 3. 挨拶と合計を計算するテスト ✓ 挨拶と合計を計算しないとだめ
3 passing (1ms)
|
3 passing
と表示されれば、本体のプログラム./index.js
と外部モジュール./lib/sample-lib.js
に亘る3つのメソッドが問題なく動作することが検証された事になります。
まとめ
という事で、今回はjavascriptやES6における、テストの書き方を簡単に解説していきました。期待した通りにプログラムが動作するか、テストコードで検証する事によって、プログラムの動作を隈なく検証することができます。
プログラムが隈なくチェックされているのか?を計測できるテスト網羅率(カバレッジ)取得という手法がありますので、次回はカバレッジについて触れていきたいと思います。