ひよっこ。

I want to…

FlexUnit4Beta1 補足第2回 – XMLListener(→JUnitListener)による出力 –

Posted by hikaruworld : 2009 7月 8

お詫びと補足

この記事は当初UP後、間違いに気がついて大きく書き直してあります。
当初JUnit形式での出力はまだ不可能かと思っていましたが、
実際はJUnitListenerを利用して出力する事が可能と思われます。
なお、出来る限り元の内容を残しておこうかと思っていたのですが、修正しすぎて一部の内容を消しまってあります。


以下本文。

fxug@富山の補足 第2回になります。

IRunListenerのクラス階層

FlexUnit4Beta1では実行時のFlexUnitCoreにaddListener()の引数として、
任意のListenerを渡す事で実行結果を取得する事が可能です。
addLitener()出来るのはorg.flexunit.runner.notification.IRunListenerを実装したクラスになります。
ちなみに、FlexUnit4がデフォルトで提供しているクラスは以下の通りです。

  1. org.flexunit.listeners.UIListener
  2. org.flexunit.runner.notification.RunListener
    • org.flexunit.internals.listeners.FluintDisplayListener
    • org.flexunit.internals.TextListener
    • org.flexunit.listeners.JUnitListener
    • org.flexunit.runner.Result#Listener
  3. org.flexunit.runner.notification.async.WaitingListener
  4. org.flexunit.runner.notification.async.XMLListener

このうち1.UIListenerと2.RunListenerを除く3.と4.のクラスは、
org.flexunit.runner.notification.IRunListenerをさらに継承したインターフェイス、
org.flexunit.runner.notification.IAsyncStartupRunListenerを実装しています。

1.UIListener

これまでの記事でも利用しているように、
TestCaseBaseに対して実行結果をGUI上にハンドリングされるような動きをするようです。

2.RunListener

IRunListenerが実装されたテンプレートメソッドのようです。
ASDocには何らかのテストの前後に何らかのイベント処理を設定したい場合には
必要に応じてこのクラスを拡張するようにと書かれています。

なおRunListenerに関しては、
さらにFluintDisplayListener, TextListener, JUnitListener,Result#Listenerの4つのクラスに継承されています。

FluintDisplayListenerはおそらく統合されたFluint向けの機能と名前から勝手に解釈してスルーします(汗
TextListenerは実装からみるにコマンドライン出力に利用されているようです。
JUnitLitenerはJUnit形式で出力してくれるという事でしょうか。このクラスに関しては後で補足することになりました。
Result#Listenerに関しては外部からは参照できない内部クラスですのでこれも勝手にスルーします。

3.WaitingListener

このクラスは実装のないテンプレートクラスになっているようで
コンストラクタで5000ms遅延させた後、WaitingListener.readytureに設定し
AsyncListenerWatcher.LISTENER_READY をdispatchしているのみのようです。

その他の実装(testRunStarted, testRunFinishedなど。。。)は空になっています。
当初はこのクラスがテンプレートクラスとして利用されるのかなと思っていたのですが、
このクラスはoverrideを許可されていないのでそういった利用方法ではないようです。

4.XMLListener

に関しては出力結果をJUnitライクなXML形式で出力されるだろうと妄想しています。
実際はJUnit形式の出力はJUnitListenerで行われます。
XMLLitenerはXML形式で出力を行いますが、このXMLを誰がどう解釈するかはちょっとかりませんでした。
今後FlexUnit4独自のフォーマットに対応した何らかのアプリケーションが同梱されて出来てくるのでしょうか。。。

さて今回の話題は、このXMLListenerの使い方になります(→上記のように後ほどJUnitListenerに遷移します)。

XMLListenerの実行とその結果

とりあえず、FlexUnitCore.addListener()XMLListenerを与えて、実行してみます(必要部分のみ抜粋)。
なおこのテストはAirプロジェクトで行っています。利用しているIDEはFlashDevelop3RTM1か、FlexBuilder3です。

var core:FlexUnitCore = new FlexUnitCore();
core.addListener(new XMLListener());

但しこのまま実行しても、出力結果は以下の通りでエラーになってしまいます。

[ERROR] FlexUnit4 Listener [object XMLListener] failed to start

エラーの意味はわかりますが、理由が全くわからないのでソースを覗いて見ました(コンストラクタ部分を抜粋)。

public function XMLListener( projectName:String = "", contextName:String = "" ) {
    this.projectName = projectName;
    this.contextName = contextName;

    socket = new XMLSocket ();
    socket.addEventListener( Event.CONNECT, handleConnect );
    socket.addEventListener( IOErrorEvent.IO_ERROR, errorHandler);
    socket.addEventListener( SecurityErrorEvent.SECURITY_ERROR,errorHandler);
    socket.addEventListener( Event.CLOSE,errorHandler);
    try
    {
       socket.connect( server, port );
    } catch (e:Error) {
        trace (e.message);
    }
}

ソースコードを見ればわかりますが、XMListenerは内部でXMLSocketを生成して、XML形式のソケットを送っていることがわかります。
てっきり、ファイルか何かに書き出していると思っていたのですがそうではないようです。

おそらくIOErrorEvent.IO_ERROR,SecurityErrorEvent.SECURITY_ERRORのいずれかが発生していると考えられますので、
念のため確認をしておきます。

private function errorHandler(event:Event):void {
    // trace文を追加
    trace(event);
    dispatchEvent( new Event( AsyncListenerWatcher.LISTENER_FAILED ) );
}

以下は実行結果のログになります。

[IOErrorEvent type=”ioError” bubbles=false cancelable=false eventPhase=2 text=”Error #2031: Socket Error. URL: 127.0.0.1″ errorID=2031]

やはり思ったとおり、接続失敗で落ちているようです。
しかし、わざわざXMLSocketで通信しているのは不思議な感じがします。
FlexUnit4の正式版が出るまでにはAir版のクライアントサーバアプリを同梱してそれを起動して使うようにしようと考えているのでしょうか。
ちょっと背景が気になりますね。。。

エラーを回避

さて、今後の予想はともかく上記の状態ではXMLSocketサーバがないことには話になりません。
原因がXMLSocketサーバに接続できていないとのことでしたので、
XMLSocketサーバを簡単に書いてテストしてみます。

ここはJavaで書いています。
Adobeのリファレンスにも(Javaでの)簡単なXMLSocketサーバの書き方の説明があるので参考になるかと思います。
*ソケット接続 – Java XML ソケットサーバーの作成および接続

なお、XMLListenerのソースを見ればわかると思いますが、XMLListener内部で生成されるXMLSocketは8765ポートを利用していますので、
それに併せる形で書く必要があります。

[Inspectable]
public var port : uint = 8765;

[Inspectable]
public var server : String = "127.0.0.1"; //this is local host. same machine

基本的にはソケット接続とほぼ同じですが、検証に利用した手抜きのソースを張っておきます。

import java.io.*;
import java.net.*;

public class SimpleServer {
    private static final int SERVER_PORT = 8765;

    public static void main(String[] args) throws Exception {
        new SimpleServer(SERVER_PORT);
    }
    public SimpleServer(int port) throws Exception {
        System.out.println(">> Starting SimpleServer");
        ServerSocket socket = new ServerSocket(port);
        Socket incoming = socket.accept();
        BufferedReader readerIn = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
        System.out.println("Enter EXIT to exit.\r");

        String str;
        while ((str = readerIn.readLine()) != null) {
            System.out.println("Echo: " + str + "\r");
        }
        incoming.close();
        socket.close();
    }
}

XMLSocketサーバを起動した上で再度テストを実行してみます。
以下はログになります(複数のテストを実行しています、これは使ったテストケースが別のため。)。

[INFO] FlexUnit4 test::HamcrestTest.assertBetweenFalse .
[INFO] FlexUnit4 test::HamcrestTest.assumTahtTestNG .
[INFO] FlexUnit4 test::HamcrestTest.assumTahtTestNG I
[INFO] FlexUnit4 test::HamcrestTest.assertThrow .
[INFO] FlexUnit4 test::HamcrestTest.assertThatAnything .
[INFO] FlexUnit4 test::HamcrestTest.assumeThatTestOK .
assumeThatOK….
[INFO] FlexUnit4 test::HamcrestTest.assertBetweenTrue .
[INFO] FlexUnit4 test::HamcrestTest.assertDescribedAs .
[INFO] FlexUnit4 test::HamcrestTest.assertThatIsA .
[INFO] FlexUnit4 test::HamcrestTest.assertThatAllOf .
[INFO] FlexUnit4 test::HamcrestTest.assertEither .
[INFO] FlexUnit4 test::HamcrestTest.assertThatGreaterThan .
[INFO] FlexUnit4 test::HamcrestTest.assertNot .
[INFO] FlexUnit4 test::HamcrestTest.assertThatAnyOf .
[INFO] FlexUnit4 test::HamcrestTest.assertThatBoth .
[INFO] FlexUnit4 Time: .102
[INFO] FlexUnit4 OK (14 tests)

無事実行されたことが確認できました。

XMLSocketサーバ側はどうなっているでしょうか。
送られた文字列を標準出力する簡単な実装なので、ログを確認してみます。

<startTestRun totalTestCount='14'  projectName='' contextName='' />
    <testCase name='assertBetweenFalse' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assumTahtTestNG' testSuite='test::HamcrestTest'  status='ignore'/>
    <testCase name='assumTahtTestNG' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertThrow' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertThatAnything' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assumeThatTestOK' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertBetweenTrue' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertDescribedAs' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertThatIsA' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertThatAllOf' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertEither' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertThatGreaterThan' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertNot' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertThatAnyOf' testSuite='test::HamcrestTest'  status='success'/>
    <testCase name='assertThatBoth' testSuite='test::HamcrestTest'  status='success'/>
<endOfTestRun/>

こちらもXMLSocketが正常に送られていることがわかります。

但し、疑問点が1つ。
FlexUnit4をXMLListenerで出力を行った際はJUnit4と同様の書式で出力されると予想していたのですが、
そうではないようです。

これは、正式版に向けてJUnitと同様の形式でFlexUnitが実装されていくのか、
それともFlexUnit4独自のレポート形式になるのかどちらになるのでしょうか。。。

JUnitListenerによるレポート出力

IRunListenerを実装したRunListenerを継承したJUnitListenerを用いてJUnit形式の出力を行います。
ただし、このクラスを含むライブラリFlexUnit4CIRunner.swcはダウンロードした版には含まれておらず、
直接ソースから取得する必要がありますので注意してください(探しても見つからない訳だ。)。

JUnitListenerもXMLSocketを利用して通信を確立させていますので、同様のSocketServerを起動しておく必要があります。
また、JUnitListenerの接続ポートは現時点では1024が指定されています。
以下が出力結果になります(これも慌てて確認したのでテストクラスが違います)。

<testsuite errors="0" failures="0" name="exception.ExceptionHandlingTest" tests="2" time="0">
  <testcase classname="exception.ExceptionHandlingTest" name="illegalOperationErrorTest" time="0"/>
  <testcase classname="exception.ExceptionHandlingTest" name="exceptionTest" time="0"/>
</testsuite>
<testsuite errors="0" failures="0" name="exception.ExceptionHandlingTest" tests="2" time="0">
  <testcase classname="exception.ExceptionHandlingTest" name="illegalOperationErrorTest" time="0"/>
  <testcase classname="exception.ExceptionHandlingTest" name="exceptionTest" time="0"/>
</testsuite>

このような形でJUnit形式での出力がおこわれます。
(実際に解釈されるかは未確認なので注意。なんかたりない気がする。。。)

ところで勉強会でも少し話しましたが、ようやくFlashBuilder4でFB-18873がfixされたようですので、次のビルド版が楽しみです。

以上。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

 
%d人のブロガーが「いいね」をつけました。