Edited at

JavaScriptで(そしてどんな言語でも同じで)世界一簡単なテストフレームワークを作って使おう

More than 1 year has passed since last update.


はじめに

どんな言語でもテストコードは簡単につくれます。

[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関数をテストするコード、全文を書いておきます。


コード全文


test.HTML


<!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関数は完成となります。

これがテストドリブン開発と言われるものです。

テストコードというのは、こういうことです。

これのどこが難しいのか。ということになります。

テストフレームワークのインストール死体人はしてもいいけど、本質がわかれば、そんなのいらないよ。


最後に

実例として、テストコードをけっこう書いているライブラリを作っています。

standard-software/stsLib.js

また、自分は以前はDelphi使いだったので、昔に、こんなコードを書いたことがありました。

例えば、IPアドレス判定のテストコード

ipアドレスが正しいかどうかを判定するには?

Delphi読めなくても、Check関数の羅列されたテストコードの部分は読めるでしょう。isSaveIPの中身の実装はいろんな方法があるにせよテストがOKだったら、その関数は使える。ということになります。

他にも、行末禁則行頭禁則を考慮した文字列折り返しとか書いたことあります。

WordWrap.dll

テストコードを書かなければ、isSaveIP にしても、行末禁則行頭禁則を考慮した文字列折り返しにしても、完全な仕様を満たすコードを書くのはかなり困難です。テストコードがあればそれは可能です。


追記

リンク先が10年近く前の時代のものですね…

他にも、こんなことしたことあります。

かなり複雑なオブジェクトの情報表示にTreeViewを使用していたプログラムがあって、その改良をしていました。

コードがかなり難解だったので、大幅にリファクタリングしてシンプルにしたのですが、元データが複雑すぎて情報膨大だったので、リファクタリング前と後で全く同じ動作をしてるかどうかわからなかったんです。

そこで、TreeViewの項目をすべて文字列として出力できるコードを持ってきて、リファクタリング前コードとリファクタリング後コードを共存させて、TreeViewの項目をすべて文字列にして比較する、みたいな動作も実現させたことがあります。

ここのシステムでした。東京大学スポーツ先端科学研究拠点

今まで自分は、このテストコードを利用した開発方法に何度も助けられました。自分のコードの品質を上げることができましたし、安心して比較的不具合の少ないプログラムが作れるようになります。

このやり方を知れば、知らないときよりも、みなさんの開発能力を一段も二段も引き上げることができると思います。

追記終わり。


テストコードがなければ、開発した成果物の品質は保てないです。

テストコードのない関数やメソッドなど、石のタヌキだ。というわけです。


続き

この記事の続きを書きました。

JavaScriptで世界一簡単なテストフレームワークに例外捕捉機能追加した - Qiita