月別アーカイブ: 2014年2月

テストで検出したバグをコンパイラ警告として出力してくれるHaxeライブラリ、NanoTestを公開しました

FlashDevelopcapture-20140201-150704


GUIを使ってテストのデバッグがしたい

Haxeには標準で、haxe.unitというテスト用のライブラリがあります。とてもシンプルなライブラリです。低い敷居でテストを導入できて良いのですが、もの足りないなーと思うところもあります。

何がもの足りないのか?

足りないのはGUIです。グラフィカルなユーザーインタフェースです。黒い画面上に表示されたメッセージを眺めて、ファイルを探して、失敗した行を探して、1つ1つバグを潰していくのは、なんとも骨が折れます。

「ずらっとならんだメッセージをクリックしたら、テスト失敗した行にすぐ飛べる!」とか「失敗行を赤線で示してくれる!」とかそういうGUIがあればもっと楽に、簡単にテストができるわけです。コンパイルエラーでは、エラー行へジャンプする機能も、エラー行をハイライトしてくれる機能もIDEについています。コンパイルエラーと同じように、テストの失敗も表示してくれればデバッグもはかどるわけです。

うれしいことにHaxeのコンパイラはそれを実現できる機能があります。Haxeには、コンパイル前にコードを実行して、その際にコンパイルエラーやコンパイラ警告を出力することができる機能があります。

それが、これ、Compiler Configuration with Macros。いわゆるマクロです。コンパイル中ではなく、コンパイル前に動作するマクロなので、自分はコンパイル前マクロと呼んでいます。今回は、このコンパイル前マクロでつかうテスト用のライブラリNanoTestを作りました。


NanoTest(ナノテスト)

ソースコード:https://github.com/shohei909/NanoTest
ライセンス:MIT Lisence

NanoTest(ナノテスト)の特徴は以下のとおり

  • テストの書き方はhaxe.unitとほぼ同じ。すでにhaxe.unit用に記述したコードがあるならばTestRunnerをNanoTestRunnerに、TestCaseを、NanoTestCaseに置き換えれば、同じように動作します。シンプルなので学習コストも低いです。
  • NanoTestをマクロとして実行することで、テストの失敗をコンパイラ警告やコンパイルエラーとして出力することができます。FlashDevelopだろうとIntelliJ IDEAだろうと、いつもと同じUIでテスト失敗が警告されるので、快適にデバッグをすることができます。

インストール

haxelibをつかってインストールすることが可能です。コンソール上で以下のコマンドを打ち込んでください。

haxelib install nanotest

使い方

基本的な、テストの書き方はHaxeマニュアルのWriting Unit Testsとほぼ同じです。

NanoTestの場合、以下のようなファイルをsample/TestSample.hxとして保存します。

package sample;
import shohei909.nanotest.NanoTestRunner;
import shohei909.nanotest.NanoTestCase;
 
class TestSample {   
    static function main(){
        var r = new NanoTestRunner();
        r.add(new TestFoo());
        r.run();
    }
}
 
class SampleCase extends NanoTestCase {
    public function testBasic(){
        assertEquals( "A", "A" );
    }   
}

これを、以下のようなhxmlファイルでコンパイルして実行すれば、haxe.unitと同じようにテストが出来ます。

-neko testSample.n 
-main TestSample
-lib nanotest

上記のテストをマクロとして実行したい場合、hxmlを以下のように書き変えます。

--no-output
--macro sample.TestSample.main()
-lib nanotest

“–macro”で指定した関数が、コンパイル前に実行させれて、そこでテストの失敗があればコンパイラ警告としてそれが出力されます。

このhxmlを使ってIDEがコンパイルするように設定すれば、IDEがコンパイラ警告としてテスト失敗を出力してくれるので、コンパイルエラーをとりのぞくのと同じようにテストのデバッグを行うことが出来ます。

※ FlashDevelopでhxmlを利用する方法は、ActionScript入門Wiki – FlashDevelopでHaxeプロジェクトを作成するで詳しく紹介されています。

より高度な使い方

テスト失敗を、コンパイル警告ではなくコンパイルエラーとして出力する

NanoTestRunnerのコンストラクタの引数に、NanoTestRunner.error関数を渡しましょう。

こんな風に

var r = new NanoTestRunner(NanoTestRunner.error);

コンパイル警告ではなくコンパイルエラーを出力する設定は、nightlyビルドのような自動ビルドをしたい場合に役に立ちます。つまり、テスト失敗時にコンパイルエラーになるようにしとけば、まちがってユーザーにバグを含むビルドを配布することを防げるので、安心して自動ビルドができます。

unit.haxe.TestCaseには無い関数について

NanoTestCaseは、unit.haxe.TestCaseと同じように使用することが出来ますがunit.haxe.TestCaseにはない追加の関数をもっています。

assertThrows( func:Void->Void, ?isSuccess:Dynamic->Bool, ?p : PosInfos )
funcを実行した場合に例外が投げられることをテストします。さらにisSuccessを設定した場合には、投げられた例外が正しいかどうかを、catchしたオブジェクトをisSuccess関数に渡してテストします。
globalSetup()
テストケースのクラスが複数持っているテスト用のメソッド(“test”ではじまるメソッド)の内、一番最初のメソッドが呼び出される前に呼び出されるメソッド。overrideして使う。
globalTearDown()
テストケースのクラスが複数持っているテスト用のメソッドの内、一番最後のメソッドが呼び出された後に呼び出されるメソッド。overrideして使う。
success( ?p:PosInfos )
テスト成功を出力します。
fail( message:String, ?p:PosInfos )
テスト失敗を出力します。
error( d:Dynamic )
テスト中に発生した例外を出力します。

またTestCaseとは異なり、assertEquals関数がEnumの比較をサポートしています。

注意点

マクロを使ったテストは、あくまでNekoに出力した場合のプログラムをテストしていることになります。FlashやJavaScriptなどその他のターゲットを使用している場合、そのターゲットに依存したコードについてはマクロではテスト出来ません。NanoTestでは、haxe.unit同様、実際にそのターゲットに出力した上で実行してテストするのも可能なので、ターゲット依存のコードについてはマクロを使わずにテストするようにしてください。

更新情報

v0.1.2(2014/02/02 17:29)
swf上で動作させた場合に上手く動かないバグがあったので修正。
v0.1.3(2014/02/02 22:05)
run関数を呼び出す前にassertできるようになりました。これにより非同期のテストが、書きやすくなりました。