latest log

酩酊状態で書いたエンジニアポエムです。酩酊状態で読んでください。

mofmof.js のUnit Test機能

mofmof.js にはユニットテスト機能があり、同期/非同期テストの混在や遅延評価もシンプルに記述できます。

以下のコードは、http://mofmof-js.googlecode.com/svn/trunk/test/base.js.htm でテストできます。

同期/非同期の混在

String#test は String#stream の機能を流用して実装されており、
同期/非同期のテストを混在する事ができます。

String#stream と異なり、項目が false を返しても最後まで実行します。

テストしたいを目的に応じて、 関数, 配列, 真偽値 の何れかで定義します。

"関数で評価 > 配列の要素2つを比較 > 真偽値評価".test({
    args: {
        msg: "hello"
    },
    "関数で評価": function() {
        return this.args.msg === "hello"; // -> true
    },

    "配列の要素2つを比較": ["aaa", "aaa"], // -> true

    "真偽値評価": 123 === 123  // -> true
});

実行結果です。

[ 02-14T09:45:25.484Z ]:┌ 関数で評...()
[ 02-14T09:45:25.485Z ]:│ 関数で評...[ 関数で評価, true ]
[ 02-14T09:45:25.485Z ]:│ 関数で評...[ 配列の要素2つを比較, true ]
[ 02-14T09:45:25.486Z ]:│ 関数で評...[ 真偽値評価, true ]
[ 02-14T09:45:25.487Z ]:└ 関数で評...(span:00.003)
関数で定義

関数は同期/非同期テスト用です。 this を使って hash に定義されている変数を参照可能です。また非同期に結果を返す事ができます。

"関数で遅延評価".test({
    args: {
        msg: "hello"
    },
    "関数で遅延評価": function(callback) {
        3..lazy(this, function() { // 3秒後に関数を遅延実行, 関数内部の this を指定

            callback(this.args.msg === "hello"); // callback(true)

        });
    }
});

実行結果です。

[ 2012-02-14T09:46:08.208Z ]: ┌ 関数で遅延評価()
[ 2012-02-14T09:46:11.208Z ]: │ 関数で遅延評価[ 関数で遅延評価, true ]
[ 2012-02-14T09:46:11.226Z ]: └ 関数で遅延評価(span:03.018)
配列で定義

2つの要素をもつ配列を指定すると Type.isLike(配列の先頭要素, 配列の2番目の要素) で比較を行い、結果を true / false として評価します。

"配列の要素2つを比較".test({
    "配列の要素2つを比較": ["aaa", "aaa"] // -> true
});

実行結果です。

[ 2012-02-14T09:47:01.915Z ]: ┌ 配列の要素2つを比較()
[ 2012-02-14T09:47:01.916Z ]: │ 配列の要素2つを比較[ 配列の要素2つを比較, true ]
[ 2012-02-14T09:47:01.916Z ]: └ 配列の要素2つを比較(span:00.001)
真偽値で定義

真偽値も使えます。

Type.isLike 以外の関数で評価する場合などに使用できます。

"anagram".test({
    "anagram": "JavaScript".anagram("JScript") // -> true
});

実行結果です。

[ 02-14T10:15:47.555Z ]:┌ anagram()
[ 02-14T10:15:47.557Z ]:│ anagram[ anagram, true ]
[ 02-14T10:15:47.559Z ]:└ anagram(span:00.004)

this.log でログを出力できます

String#test は、this.log(...) とすることでログを出力できます。

"a > async1 > async2 > b > c".test({
    args: {
        msg: "hige"
    },
    a: function() {
        return this.args.msg === "piyo"; // -> false
    },
    b: ["aba", "aaa"],  // -> false
    c: 123 === 456,     // -> false
    async1: function(callback) {
        2..lazy(null, callback);
    },
    async2: function(callback) {
        2..lazy(this, function() {

            this.log("LOG OK!");

            callback(true); // -> true
        });
    }
});

実行結果です。

[ 14T09:52:19.082Z ]:┌ a > async1 > async2 > b > c()
[ 14T09:52:19.105Z ]:│ a > async1 > async2 > b > c[ a, false ]
[ 14T09:52:21.106Z ]:│ a > async1 > async2 > b > c[ async1,  ]
[ 14T09:52:23.106Z ]:│ a > async1 > async2 > b > c[ LOG OK! ]
[ 14T09:52:23.107Z ]:│ a > async1 > async2 > b > c[ async2, true ]
[ 14T09:52:23.108Z ]:│ a > async1 > async2 > b > c[ b, false ]
[ 14T09:52:23.109Z ]:│ a > async1 > async2 > b > c[ c, false ]
[ 14T09:52:23.110Z ]:└ a > async1 > async2 > b > c(span:04.028)

存在しない関数や項目を指定するとエラーで中断します

存在しない項目があればテストを中断します。

"a > b> c".test({

    a: true,
    b: true,
//  c: true
});

実行結果です。

[ 2012-02-14T09:53:31.110Z ]: ┌ a > b> c()
[ 2012-02-14T09:53:31.110Z ]: │ a > b> c[ a, true ]
[ 2012-02-14T09:53:31.111Z ]: │ a > b> c[ b, true ]
[ 2012-02-14T09:53:31.112Z ]: │ a > b> c[ c, ERROR ]

Array#test でもっとシンプルに


String#test の簡易版、Array#test もあります。

以下のように関数名を並べるだけでテストできます。

function async1(callback) {
    2..lazy(null, callback);
}

function async2(callback) {
    2..lazy(this, function() {

        this.log("OK!");
        callback(true);

    });
}

[async1, async2].test(); // テスト実行

実行結果です。

[ 14T09:57:19.675Z ]:┌ async1 > async2()
[ 14T09:57:21.676Z ]:│ async1 > async2[ async1,  ]
[ 14T09:57:23.676Z ]:│ async1 > async2[ OK! ]
[ 14T09:57:23.677Z ]:│ async1 > async2[ async2, true ]
[ 14T09:57:23.678Z ]:└ async1 > async2(span:04.003)

例外発生をテストする

例外が発生することをテストしたいケースがあります。そのような場合は try ~ catch で囲ってください。

function catchError() {
    try {
        throw new Error("ERROR");
    } catch (err) {
        return true;
    }
    return false;
}

[catchError].test();

実行結果です。

[ 02-14T10:00:33.294Z ]:┌ catchError()
[ 02-14T10:00:33.295Z ]:│ catchError[ catchError, true ]
[ 02-14T10:00:33.296Z ]:└ catchError(span:00.002)

まとめ

いかがだったでしょうか。

従来の Unit Test に比べ、コード量も少なく環境も汚染しません。

(ε・◇・)з テストめんどくさー

と言わずにどんどんテストしましょう → (ε・◇・)з