すがブロ

sugamasaoのhatenablogだよ

FlexUnitを試してみた

まずは準備から

ここから FlexUnit4 の zip を落とす

公式のドキュメント

その他参考になったページ

Zip を解答して

好きな場所に配置してください。必要なのは libs にある swc なファイルのみになります。
使う場合は二パターンあって -compiler.library-path 追加するパスに特定の場所をおいて(/opt/hoge/flexunit/libs) のように、システム全体で共通の値を使うようにするか、各プロジェクト毎に libs フォルダに置くか。
普通に Flex を使うと後者になると思うけど、毎回コピーするのも面倒だ、という場合は、共通の場所に置いておくと良いと思う。

ざっくり手順

  • テストを実行するテストランナーを作る
  • テストファイルを作る
  • テスト対象のファイルを実行する
  • テストを実行する

あと、テストを行い易くするため、rascut の導入を強くオススメします。

ファイル構成はこんな感じ

ソース一式は misc/flexunit_sample at master · sugamasao/misc · GitHub にあります。

|-- libs
|   |-- FlexUnit1Lib.swc
|   |-- FlexUnit4.swc
|   |-- FlexUnit4UIListener.swc
|   `-- hamcrest-1.0.2.swc
`-- src
    |-- FlexSample.mxml
    |-- TestRunner.mxml # テストランナー
    |-- sample
    |   |-- Calculate.as
    |   `-- Fuga.mxml
    `-- test
        |-- FlexSampleTest.as # テストクラス
        |-- TestSuiteAll.as # テストスイート
        `-- sample
            |-- CalculateTest.as # テストクラス
            `-- FugaTest.as # テストクラス

テスト作成の流れ

まず、TestRunner を作成し、 run メソッドで実際にテストを実行する。その際、個別にテストクラスを引数にとっても良いし、テストスイートを渡しても良い。
今回はテストスイートを渡すようにした。

テストを実行するには

TestRunner.mxml をコンパイルして実行すれば良い。
そのため、rascut で更新の都度コンパイル→実行を繰り返せば ruby の autotest のように、常時テストが実行できてすばらしい!

rascut -s -c -compiler.library-path+=./libs ./src/TestRunner.mxml

こんな感じのコマンドで実行して、ブラウザで開いておけばOKです。

テストスイート

なんの事はなくて、テストを public な変数として持てば良い。

テスト(普通の)

いわゆる足し算メソッドとかをテストする場合。まーほとんど使わないが。。。

[Test(description="計算のテスト")]
public function testAdd():void
{
   Assert.assertEquals(2, target.add(1, 1));
}

target は [Before] タグのついたメソッド(テストケース毎に実行される)で生成したオブジェクト。
たいがいのサイトでも紹介されてる手法ですね。

テスト(UI)

UI の場合はちょっと手順が違う。

準備(before)

まず、Before 等で、テスト用のコンポーネント内に、テスト対象のオブジェクトを addChild する。

[Before(async,ui)]
public function alsoRunBeforeEveryTest():void {
    trace("before");
    target = new Fuga();
    Async.proceedOnEvent( this, target, FlexEvent.CREATION_COMPLETE, 500);
    UIImpersonator.addChild(target);
} 

対象が Sprite とかだったら、一旦 UIComponent 等に突っ込んでから UIImpersonator に突っ込むと良い。
あとは、一応 CREATION_COMPLETE イベントが走るまでは待ってあげる*1

実行

[Test]タグに ui や async をつけて UI のテストであることを明示しておく。
あとは Async.handleEvent にて第二引数に対象オブジェクトを、第三引数に発火してくるイベントを書いて、第四引数にイベント発火時の検証メソッドを渡す。
検証の準備ができたら dhispatchEvent で擬似的にボタンが押された、とかを偽装するためにイベントを発火してあげる。
もちろん、自分で作ったオリジナルのイベントだって発火できるし、待ち受けることもできる。

[Test(description="ボタンが押下されたことを確認するテスト", async, ui)]
public function buttonHandlerTest():void {
  // 発火するイベントをウォッチする
  Async.handleEvent(this, target, MouseEvent.CLICK, buttonHandlerTestHandler, 500);
 
  // テストしたいイベントを実際にディスパッチして実行する
  target.fugabutton.dispatchEvent( new MouseEvent(MouseEvent.CLICK, true));
}

実際にイベントが発火したら、検証用メソッドで検証する。
こっちは別に[Test]とかは不要。

private function buttonHandlerTestHandler(e:Event, passThroughData:Object):void {
  trace(e, passThroughData);
  Assert.assertEquals(e.type, MouseEvent.CLICK);
}

この例だと想定したイベントタイプが発生していることを検証しているけど、他のコンポーネントにどのような影響を与えているかもここで検証できる。

ここではボタンを押された結果、別のコンポーネントの値が変わることを検証している。

だいたいの手順は

こんな感じです。他にも一連の動きをシナリオとして定義してテストしたりもできるようなのですが、イマイチ情報も少ないのでちょっと調べきれてません。。。

その他(hamcrest)

hamcrestって良く分かってないんだけど、Java で実装されているもののASへの移植版っぽい。AssertThat をもっとわかりやすく書こうぜ!みたいなヤツで、検証メソッドとして便利なのがそろってる。
まったくつかいこなせてないけど、as_logger/src/test/com/github/sugamasao/as_logger at master · sugamasao/as_logger · GitHub でちょっと使いました。

いまのところこんな感じです><

イマイチ日本語の資料も少ないので、ここ間違ってるよ!とかあれば教えて下しあ!

*1:Async.proceedOnEventのとこね