ひよっこ。

I want to…

FlexUnit4(beta1)でのTheoryとDataPoint

Posted by hikaruworld : 2009 7月 7

fxug@北陸in富山で発表した資料のうち肝心なとこが抜けていて、@shoitoや、@coelacanthに突っ込まれたので、暫くはblogで補足していきます。

といいつつ、以下の内容は動作確認をしながら検証しただけなので、本当にあっているかどうかは自信がないので。
間違っているかもしれません。(ソースまでは覗いていない。。。)

目次

1.[Theory]と[DataPoint]
2.[DataPoints]
3.テストの引数に複数パラメータを与える
4.[Theory]と[Test]の併用
5.疑問点

1.[Theory]と[DataPoint]

FlexUnit4の新機能として、[Theory][DataPoint]というものが提供されています。
【Theory】は和訳すると【定理、理論】と訳されますが、このFlexUnit4のメタタグで言われるTheoryとは、
上記のようにメタ[DataPoint]が成り立つための理論と解釈すればいいのかなと思います。

実際の挙動としては[DataPoint]で定義された値を[Theory]で検証を行うといった機能性を持っているようです。

ただ、この使い方はドキュメントを見ただけではいまいちわかりにくいものがあります。
というかドキュメントのサンプルソースを見ても全く挙動がわかりません(汗。。。
のですが、サンプルソースを書かないと話が進まないので以下ソースです。

package test 
{
    import org.flexunit.assertThat;
    import org.flexunit.assumeThat;
    import org.flexunit.experimental.theories.Theories;
    import org.hamcrest.core.isA;
    import org.hamcrest.core.not;
    import org.hamcrest.number.greaterThan;
    import org.hamcrest.object.instanceOf;
    
    /**
     * Theoryの実行確認クラス
     * @author hikaruworld
     */
    [Suite]
    [RunWith("org.flexunit.experimental.theories.Theories")]
    public class TheoryTest 
    {
        //--------------------------------------------------------------------------
        //
        //  DataPoints
        //
        //--------------------------------------------------------------------------
        [DataPoint]
        public static var number:Number = 5;
        [DataPoint]
        public static var number2:Number = 10;
        [DataPoint]
        [ArrayElementType("String")]
        public static var stringValues:Array = ["one","two","three","four","five"];
        //--------------------------------------------------------------------------
        //
        //  Theories
        //
        //--------------------------------------------------------------------------
        /**
         * この理論の検証は[DataPoint]がこのメソッドの引数と一致するStringの場合にのみ実行される。
         * ここで注力するのは、[DataPoint]の型がNumberのものは検証されるが、[DataPoint]の型がArrayのものは検証されない点
         * 以下は実行結果の出力.
         * TODO...
         */
        [Theory]
        public function testNumber( numberValue:Number ):void 
        {
            trace("check theories ...:" + numberValue);
            assumeThat(numberValue, isA(5));
            trace( "numberValue check Ok is... : " + numberValue );
        }
        /**
         * このテストは、[DataPoint]で指定されている型がArrayの場合にのみ実行され検証が行われる。
         *
         */
        [Theory]
        public function testArray(arrayValue:Array):void
        {
            //TODO...
            //assumeThat();
        }
     }
}

この実行結果は以下の通りになります。

7/7/2009 10:29:02.781 [INFO] FlexUnit4 test::TheoryTest.testNumber .
check theories ...:5
numberValue check Ok is... : 5
check theories ...:10
7/7/2009 10:29:02.828 [INFO] FlexUnit4 test::TheoryTest.testArray .
7/7/2009 10:29:02.843 [INFO] FlexUnit4 Time: .056
7/7/2009 10:29:02.843 [INFO] FlexUnit4 OK (2 tests)

ログを見てもらえばわかると思いますが、これは上記のようにメタタグ[DataPoint]が設定されているプロパティに対して、
メタタグ[Theory]が付与されているメソッドで引数の型が一致する[DataPoint]の検証が行われています。

そして、TheoryTest.testNumberでは[DataPoint]が付与されているnumber,number2の検証を行っており、
assumeThat()が一致しないnumber2に関しては以降の処理が実行されず、以下のログが出力されていないのがわかります。

numberValue check Ok is... : 10

どうやらこの辺りは、引数から暗黙に解釈されているらしく混乱しました。
但し、暗黙的に解釈しているとしても引数の型を「Object」や「*」を指定した場合には下記の警告にもあるようなエラーが発生しました。
内部的にはis演算子を利用して、インスタンスを比較しているのかもしれません。

警告

ちなみに、もし[Theory]の引数に対応する[DataPoint]が存在しなかった場合、
以下のエラーが投げられることになります。

7/7/2009 13:01:26.062 [WARN] FlexUnit4 1 test::TheoryTest.hoge Never found parameters that satisfied hoge method assumptions.  Violated assumptions:

2.[DataPoints]

[DataPoints]は配列要素の中身を一個ずつ利用する際に用いられるようです。
以下ソースです(必要な部分のみ抜粋)。

[DataPoints]
[ArrayElementType("String")]
public static var stringValues:Array = ["one", "two", "three", "four", "five"];

[Theory]
public function checkStr(str:String):void
{
	trace( "str : " + str );
}

以下はログになります。

7/7/2009 16:03:44.468 [INFO] FlexUnit4 test::TheoryTest.checkStr .
str : one
str : two
str : three
str : four
str : five

上記の通り、[DataPoints]で指定されている配列が分解されて与えられ5回実行されていることがわかります。

もし、配列ではない型に[DataPoints]を与えた場合にどうなるか試してみましたが
まず、intやNumberのようなデータ型やクラスの場合だとどの引数にも合致せず正常に実行されませんでした。

3.テストの引数に複数パラメータを与える

これを利用することでテストメソッドに複数のパラメータの組み合わせを与えることが可能になります。
(必要な部分のみ抜粋)

[DataPoint]
public static var number:Number = 5;
[DataPoint]
public static var number2:Number = 10;
[DataPoint]
/**
 * このテストはNumber型の[DataPoint]の組み合わせを引数に取り実行される。
 */
[Test]
public function hoge(val:Number, val2:Number):void
{
	trace( "val : " + val );
	trace( "val2 : " + val2 );
}

以下はログ

7/7/2009 13:17:24.546 [INFO] FlexUnit4 test::TheoryTest.hoge .
val : 5
val2 : 5
val : 5
val2 : 10
val : 10
val2 : 5
val : 10
val2 : 10

見てもわかるように、5-5,5-10,10-5,10-10[DataPoint]上に設定されている全ての組み合わせ(6パターン)が
実行されていることがわかります。

動き的には、TestNG@Parametersや、@DataProviderといえばわかる方にはわかりやすいのではないでしょうか。

4.[Theory]と[Test]の併用

ここがちょっと疑問点なのですが・・・
[Theory]の意味や概要を確認していると,[Theory]による検証が失敗した場合は[Test]が実行されないと考えてました。
しかし、そういった挙動ではないようです。以下はソースです(相変わらず抜粋)。

[DataPoints]
[ArrayElementType("String")]
public static var stringValues:Array = ["one", "two", "three", "four", "five"];
/**
 * Theoryによる値の検証
 */
[Theory]
public function checkStr(str:String):void
{
	assumeThat(str.length, greaterThan(4));
	trace( "str : " + str );
}
/**
 * テストの実行
 */
[Test]
public function testStr(str:String):void
{
	trace( "str : " + str );
	Assert.assertTrue(str.length > 0);
}

以下のログを参照ください。

7/7/2009 16:21:17.906 [INFO] FlexUnit4 test::TheoryTest.testStr .
str : one
str : two
str : three
str : four
str : five
7/7/2009 16:21:17.921 [INFO] FlexUnit4 test::TheoryTest.checkStr .
str : three

[Theory]での前提条件検証assumeThat(str.length, greaterThan(4));によって
FlexUnit4 test::TheoryTest.checkStr ではthree以外が無視されていることがわかります(正確には無視ではなく、処理されないですが)。

その一方でその前提条件精査に関わらず、FlexUnit4 test::TheoryTest.testStrが実行されてしまっているのがわかります。
もうひとつ疑問なことが、[Theory]よりも[Test]が先行して実行されてしまっている点です。

これはRunWithでTheoriesを指定することを考えても、[Theory]と[Test]は混ぜるな危険ということになるのでしょうか?
うーん。。。
この辺りは後でソースかテストソースを覗いてみようかと思います。

5.疑問点

1. TheoryとTestの併用に関して
2. [DataPoints]による配列分解の実装

以上ー。
気が向けばまとめます。

コメントを残す