はじめに
node.js にテストフレームワーク導入する方法って話。
普通にやれば困らずに出来る範囲なんだけど
「普通」に未だ辿りついてない私レベルの方々の参考に成れば!、
っていう話。
実行方法と、実行していく中でハマッた事例を記載。
ネットをザッと検索した印象では、現状(2015~2016)だと
「とりあえずMochaでいんじゃね?」っと感じられたので、
ここでは数あるJavaScriptのテストフレームワーク中で
mochaを採用する。
なお、mochaは、jQuery環境(ブラウザ環境)でも使えるみたい。
でも以下ではコマンドライン前提(node.js)。
Mochaの実行ファイルのありかと、テストコードの実行方法
npm install mocha
でローカルインストールする。
多くの解説サイトでは、この直後に「mocha
でテストを実行可能」って
書いてあるけど、それはLinux環境前提な。
Windows環境の場合は、パスが通っていないのにで、NG。
実行ファイルが「node_modules.bin\mocha」辺りにあるので、
「node_modules.bin\ 」をNODE_PATH環境変数に設定するか、もしくは、
以下を記述したバッチファイル mohca.bat
を test フォルダの上位に置いておく。
@node_modules\.bin\mocha %1 %2 %3 %4 %5 %6 %7 %8 %9
※配置は以下を前提。
mocha.bat
+node_modules
+src
| +― 被テストコード.js
|
+test
+― テストコード.js
これで、コマンドプロンプト上から
mocha
で実行可能になる。
※もちろんテストコード.js」が無ければ何も走らない。
テストコードは、以下のようにして書くが、詳細は割愛。
describe( "テストグループ。ファイル名とか", function(){
describe( "メソッド名とか",function(){
it( "テストの内容",function(done){
/* assert等を用いてテストコードを書く */
}
}
}
mocha test\テストドライバー.js
でファイル単位で実施可能。
指定しない場合は、testフォルダの中全部が実行される。
※以降のサンプルコードと環境は、chai
と sinon
の利用を前提。
npm chai sinon
でインストールすること。
【注意】Mocha+非同期がエラーする場合の対処方法。
正確には、
「アサーション失敗(NG)ったときに、
エラー内容の表示ではなくタイムアウトエラー扱いされる」
不具合の対処方法。
「期待値はhogeですが、実行結果はpiyoでした。失敗」
が欲しいのに、
「テスト実行はtimeoutしました」って言われて、
それじゃねーんだよ、欲しいのは!、な例。
これは、
「Promise() ベースの非同期実装している場合は、
done()を呼び出すのではなく、
Promise.then()のインスタンスを返却する」
ことで回避できるみたい。
以下、サンプルコード。
先ずはテストされるコード。1秒後にcallback()を呼ぶ。
var p = function( argv, callback ){
var promise = new Promise( function(resolve, reject){
setTimeout( ()=>{
resolve();
}, 1000 );
});
return promise.then(function(){
console.log( argv );
callback( argv );
})
}
exports.p = p;
続いて、テストコード。
最初の2つは、done();で実装。
正常系は問題ないが、異状系が「タイムアウト」って言われる。
これを修正したのが、後の2つ。
異状系でも、ちゃんと「~がNG」と言ってくれる。
const chai = require("chai");
const assert = chai.assert;
const expect = chai.expect;
const sinon = require("sinon");
const target = require("../src/promise_trial.js");
describe( "Promiseでの非同期実装のテスト方法", function(){
describe( "正常系はOK:done()利用",function(){
it( "done()で完了通知",function(done){
target.p("hoge", function(argv){
expect( argv, "正常系は問題ない" ).to.equal("hoge");
done();
});
});
});
describe( "異常系はタイムアウト扱いされる:Done()利用",function(){
it( "done()で完了通知",function(done){
target.p("piyo", function(argv){
expect( argv, "異常系を拾えない" ).to.equal("hoge");
done();
});
});
});
describe( "Rromiseをreturnすることで、エラーも正しく拾える:正常系",function(){
it( "done()ではなくPromiseで完了通知",function(){
var stub = { "callback" : ( argv )=>{ /* 処理無し */ } };
var spyCallback = sinon.spy( stub, "callback" );
var promise = target.p("hoge", stub.callback);
return promise.then( function(){
expect( spyCallback.getCall(0).args[0]).to.equal("hoge");
});
});
});
describe( "Rromiseをreturnすることで、エラーも正しく拾える:異常系",function(){
it( "done()ではなくPromiseで完了通知",function(){
var stub = { "callback" : ( argv )=>{ /* 処理無し */ } };
var spyCallback = sinon.spy( stub, "callback" );
var promise = target.p("piyo", stub.callback);
return promise.then( function(){
expect( spyCallback.getCall(0).args[0]).to.equal("hoge");
});
});
});
});
// アロー関数が混在しているのはスルーでよろ。
chaiとsinon に関する備忘録。
chai のdeepメソッドを用いてオブジェクトの中身を検証
var func = function(){ return { /* オブジェクトを返す */ }; }
expect( func(), "オブジェクトの中身で検証する" )
.to.depp.equal( { /* 期待値をザッと書く */ } );
スパイ、スタブ、モック、の利用用途との違い。
spy()
呼び出し先のメソッドが既に存在する(機能する)時に使う。
呼び出し先のメソッドはそのまま実行。
何回呼び出されたか? 何の引数で呼び出された?等をチェックする。
stub()
呼び出し先のメソッドが未だ無い、時に使う。
呼び出し先のメソッドは実行しない。
mock()
Stub()の機能にプラスして、
何回呼び出された? 何の引数で呼び出された?等をチェックする
stub() + spy() のイメージ。
(ちょっと違うかもしれないが…)
※なお、ここで「呼び出し先のメソッドを実行しない」などの
Overrite動作が出来るのは、テストコード内のみ。
非テストコードのAファイル内で参照されている変数は、
例えexports
されていたとしても
弄ることはできないっポイ(こちらで検証してみた)。
参考にしたページ
mochaとchaiとsionn関連
[Expect / Should - Chai]
http://chaijs.com/api/bdd/
[npm と Node.js 上で require を使ったモジュール読み込みの仕組みについてメモ | phiary]
http://phiary.me/npm-node-js-require-module-memo/
[javascriptのテストのはなし:Sinon.JS(その1) | Developers.IO]
http://dev.classmethod.jp/etc/javascript_testing_framework_sinonjs-1/
[jsでTDD!MochaとChaiとsinon.js入門 - lxyuma BLOG]
http://lxyuma.hatenablog.com/entry/2013/12/15/211637
[mochaとchaiの最も基本的な使い方 - 30歳からのプログラミング]
http://numb86-tech.hatenablog.com/entry/2016/06/08/155834
⇒「ブラウザでのmocha実行方法」も載ってた。
mocha+Promiseな非同期環境でエラー拾えない。
[Promise な関数を mocha でテストする - ぶるーすくりーん]
http://mid0111.hatenablog.com/entry/2015/08/23/214647
>「expect は hoge なんだけど実際は fuga だったよ」って言ってほしいのにタイムアウトエラーになる。
[Bluebirdを利用したコードをMochaでテストする - Qiita]
http://qiita.com/ysm001/items/c1070a363857a9118c89
>assertを呼び出しエラーが起きた時点でcatch handlerに飛ぼうとするため、後続のdoneが実行されずにtimeoutとなる
[Mocha - the fun, simple, flexible JavaScript test framework]
https://mochajs.org/
>WORKING WITH PROMISES