JavaScriptの単体テストフレームワーク "simpleJsUnit" で,テスト駆動開発をしよう
simpleJsUnitは,JavaScriptのコードを単体テストするためのライブラリ。
シンプルさが特徴。(たった5キロバイト)
- コマンドラインでも
- ブラウザ上でも
テストを実行可能。
以下は,このツールを使って,テストファーストなJavaScript開発を進める方法。
ダウンロード
(1)「Hello, World」プログラムを,TDDで作ってみよう
まず,入門的なテスト駆動のコーディングをやってみよう。
下記のような仕様の関数を作ることにする。
ファイル名はhoge.js,クラス名はHogeとする。
- 名前を受け取ったら,「Hello,(その名前)」と出力する。
- 引数が無効だったら,何も返さない。
ダウンロードしたunittest.jsと同じフォルダ上に,hoge.jsの名前で空のファイルを作る。
最初にやることは,Hogeを書くことではなく,Hogeのテストを書く事だ。
なぜなら,テストが仕様書だから。
TestHoge1.jsというファイル名で,以下の内容を保存。
new UnitTest({ // この単体テストファイル全体の説明 desc : "hoge.jsのテスト", // テストケース cases : [ function(){ var hoge = new Hoge(); this.a( "Hello,World", hoge.talk("World") ); this.a( "", hoge.talk("") ); } ] });
casesという配列の中に,function形式でテストケースを並べる。
1文字メソッドのa()というのはassertのこと。
テストは短く書けた方がいいでしょう?
上記のテストを実行しよう。
下記のファイルを TestHoge.wsfで保存。
<job> <script language="JavaScript" src="unittest.js"></script> <!-- テスト対象のモジュール(複数可) --> <script language="JavaScript" src="hoge.js"></script> <!-- テストケース(複数可) --> <script language="JavaScript" src="TestHoge1.js"></script> </job>
各jsファイルを読み込んでいるだけのWSFファイル。
※wsfとは何かについては,下記URLを参照。
http://language-and-engineering.hatenablog.jp/entry/20090125/1232940498
そして,(ブラウザでもいいのだがここではまず)コマンドプロンプトを開き
cscript TestHoge.wsf
と入力。cscript /nologo のようにオプションを付けてもよい。
テストが実行される。
D:\dev\>cscript.exe /nologo TestHoge.wsf D:\dev\TestHoge.wsf(11, 5) Microsoft JScript 実行時エラー: 'Hoge' は宣言されていません。
予想通り,エラー。期待通りの正常な結果。
ここでようやくhoge.jsの実装に入る。
ちょっとコーディングしたら,ちょっとテストの原則に従い,ちょっとずつ実装してみる。
hoge.js
var Hoge = function(){}; Hoge.prototype = { talk : function( str ){ return "Hello," + str; } }
中途半端なコードだが,これでテストをもう一度実行。
D:\dev>cscript.exe /nologo TestHoge.wsf OK : Hello,World NG : expected : 【】, real : 【Hello,】 total : 1 success, 1 failed finished on 2009/04/13 22:02:53
こんな感じで,1個成功・1個失敗という結果が出力される。
あとは,このfailedが出ないように元のコードを修正する。
var Hoge = function(){}; Hoge.prototype = { talk : function( str ){ return str == "" ? "" : "Hello," + str; } }
テスト実行
D:\dev>cscript.exe /nologo TestHoge.wsf OK : Hello,World OK : total : 2 success, 0 failed finished on 2009/04/13 22:09:00
これで全OKが出た。
バッチ処理でプロジェクト全体の単体テストを毎晩回したい場合は,この出力結果からtotal:を含む行を抽出し,メールで開発メンバ全員に毎日送るようにすればよい。
(Windows限定になるが。)
単体テストをブラウザで実行したい場合は,下記のようにHTMLを準備する。
<html> <body> <!-- テスト対象 --> <script language="JavaScript" src="hoge.js"></script> <!-- 単体テスト実行のために利用するモジュール --> <script language="JavaScript" src="unittest.js"></script> <script language="JavaScript" src="TestHoge1.js"></script> </body> </html>
スクリーンショット
複数のテストケースを読み込めば,複数のボタンが出現する。
failedが1個でもあれば,バーが赤くなる。
このように,
- WSFファイルによってCUIで実行する場合も,
- HTMLによってGUIで実行する場合も,
テストケースを「ファイルとして読み込むだけ」でよい。
(2)詳しい使い方
テストケース中で使える関数。
this.title("--------文字列操作系--------");
のようにすると,テスト実行結果の間に見出しを出力できる。
比較は,基本的なものが2つ。
// assertします a : function( expected, real ) { if( expected === real ) { // アサート成功時 this.a_success( expected, real ); } else { // 失敗時 this.a_failed( expected, real ); } }, // assertNotEqualします a_ne : function( expected, real ) { if( ! ( expected === real ) ) { // アサート成功時 this.a_success( "not " + expected, real ); } else { // 失敗時 this.a_failed( "not " + expected, real ); } },
- this.a( 期待値,現実値 )で等しい事を要求
- this.a_ne( 期待値,現実値 )で異なる事を要求
これ以外はどうするのかというと,各テストケース中で個別に,独自の比較関数を定義できるようになっている。
下記の例では,boo()がJSONを返すと想定している。
その返り値が{x:1, y:2}であるかどうか,a_customという関数を独自に定義して判定している。
new UnitTest({ // この単体テストファイル全体の説明 desc : "JSONを返す関数のテスト", // テストケース cases : [ function(){ this.a_custom( {x : 1, y : 2}, boo() ); } ], // 拡張判定メソッド extend_fn : { a_custom : function( obj_expected, obj_real ) { var x_ex = obj_expected.x; var y_ex = obj_expected.y; var x_re = obj_real.x; var y_re = obj_real.y; var expected = "{ " + x_ex + ", " + y_ex + " }"; var real = "{ " + x_re + ", " + y_re + " }"; if( ( x_ex === x_re ) && ( y_ex === y_re ) ) { this.a_success( expected, real ); } else { this.a_failed( expected, real ); } } } });
独自拡張の判定メソッドは,
- extend_fnの中に書く。
- a_successを呼ぶと,その比較は成功したことになる。
- a_failedを呼ぶと,比較が失敗したことになる。
という決まりのもとに書く。