はじめに
どんな言語でもテストコードは簡単につくれます。
[JavaScript テストコード]で検索すると、テストフレームワークの使い方がでてきて
「いままでテスト書くの嫌だったけど、この際、まなんでみた。」
「簡単で良かった。」
みたいな、xUnitの使い方。みたいなことが書かれていて、少し"ん?"と感じます。
なぜかというと、テストってのは、テストフレームワークを使わなきゃできませーん。という勘違いしている人が非常に多いように感じるからです。テストを書いている人の、10人中8人は、その勘違いしています。(体感)
aUnitでも、bUnitでも、cUnitでも、dUnitでも、eUnitでも、fUnitでも、
JUnitでも、NUnitでも、xUnitでも、QUnitでも、ともかくなんのテストフレームワークでもいいですけど、そんなものはどれでもいいんです。
どれもやっていることの本質は同じです。
テストコードを書くという本質を得るためにテストフレームワークの使い方なんて覚える必要なんてないです。
そこから応用したいとかいう本質+αを求めるならテストフレームワークは導入する価値はあると思います。ただ本質はシンプルで複雑さを持ち込む必要はないよ。と言いたいわけです。
世界一簡単(と思う)テストフレームワーク
テストの本質とは非常に簡単です。
テストフレームワークはいりません。というか、下記の行数だけで、これがフレームワークです。
function check(a, b) {
var message;
if (a !== b) {
message =
'A != B' + '\n' +
'A = ' + a + '\n' +
'B = ' + b;
alert(message);
}
};
JavaScriptわからない人向けに、簡単すぎる解説をしておきます。
- check関数を定義して、
- 変数aと、変数b を比較して、
- 不一致なら、メッセージを作って表示する(alert使ってる)。
- 一致なら何もしない。
という単純すぎる関数です。これで、テストフレームワーク完成です。
本質は簡単。
・2つの値を比較して、差があれば、メッセージとかログとかを出す。
・差がなければ何もしない。
これだけです。
どんな高尚なテストフレームワークも、やってることはこれとほとんど同じことです。
この単純なことをするためにフレームワークをわざわざインストールして使い方を学ばないといけないのか。っていうと、本質がわかってないからです。
(くれぐれもいいますが、単純なことから更に何か応用したいなら、テストフレームワークを選び使うといいかもしれません。)
どんなプログラミング言語でも、ifで判断してメッセージ出す、みたいなのはできます。このcheck関数と同じものを作ることはできるでしょう。
私は、check関数という名前で作りますが、名前はなんでもいいと思います。自分で作って自分で決めたら自分のオリジナルテストフレームワークです。
test関数でも、equalメソッドでも、なんでもいいでしょう。
assertというのもJavaScript以外の他言語では時々見つけるやり方です。
assertは英単語で"断言する"とか"宣言する"とかいう意味で
assert(a === 1, メッセージ);
このように書かれていて、aが1じゃなければ例外発生させる、という動作なのでテストコードには少し不向きかもしれません。
さて、この上記のcheck関数を使って、どのようにテストするか、示します。
例として作った、addFunc関数をテストするコード、全文を書いておきます。
コード全文
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script>
(function () {
var check = function(a, b) {
var message;
if (a !== b) {
message =
'A != B' + '\n' +
'A = ' + a + '\n' +
'B = ' + b;
alert(message);
}
};
var addFunc = function (value1, value2) {
return value1 + value2;
};
check(1, 1); //テスト1
check(2, 1+1); //テスト2
check(50, addFunc(5, 5)); //テスト3 NG
check(10, addFunc(5, 5)); //テスト4
alert('test finish');
}());
</script>
</head>
<body>
</body>
</html>
check関数の形がかわっていますが、あまり気にしないように。こんな書き方もできるってだけです。
テスト1、2は、問題なくテスト成功
テスト3は、テスト失敗。メッセージが出る(わざと書いた。テストコードそのものが悪い)
テスト4は、テスト成功、となります。
addFuncは単純なものなので、テストする必要はありませんが、例として書いています。
これで、addFuncの2つの引数を渡したら、足して結果を返すものだ。という動作確認ができるわけです。
例えばこういうときにも使える
単純すぎて、わかりにくいかもしれませんが、もう少し例を書くと、
数値を与えて、0~255以外の値を与えたら0を返し
0~255なら、0~1に変換して返す、という仕様のconvert関数を作りたいと、しましょう。
そういうとき、まず、テストコードを書きます。
check(0, convert(-10));
check(0, convert(-1));
check(0, convert(0));
check(1, convert(255));
check(0, convert(256));
check(0, convert(300));
check(0.5, convert(128));
こんな感じです。
そして、テストコードを書いてから、convert関数の中身を書く。
check関数がメッセージを表示する限りは、テストを通過していないので、だめです。
check関数がメッセージを表示しなくなったら、convert関数は完成となります。
これがテストドリブン開発と言われるものです。
テストコードというのは、こういうことです。
これのどこが難しいのか。ということになります。
テストフレームワークはテストの本質がわかれば、関数レベルのテストならあまり必要性がありません。
最後に
実例として、テストコードをけっこう書いているライブラリを作っています。
また、自分は以前はDelphi使いだったので、昔に、こんなコードを書いたことがありました。
例えば、IPアドレス判定のテストコード
Delphi読めなくても、Check関数の羅列されたテストコードの部分は読めるでしょう。isSaveIPの中身の実装はいろんな方法があるにせよテストがOKだったら、その関数は使える。ということになります。
他にも、行末禁則行頭禁則を考慮した文字列折り返しとか書いたことあります。
WordWrap.dll
isSaveIP にしても、行末禁則行頭禁則を考慮した文字列折り返しにしても、テストコードを書かなければ、完全な仕様を満たすコードを書くのはかなり困難です。テストコードがあればそれは可能です。