ひよっこ。

I want to…

Posts Tagged ‘AS3’

fxug@北陸in富山をやったよ。

Posted by hikaruworld : 2011 4月 24

ずいぶん間が空いてしまいましたが、
fxug@北陸in富山をやりました。

スピーカーしてくれたwacky,@itsuki_kosen,@shoito
参加してくれた皆さん、ありがとうございます。
次は6月に金沢ですので興味ある方は是非〜。

個人的には富山で初見の人に会えたのがうれしかった!

久々に話しましたが、相変わらずぐだぐだに。
もっと練習しないとなー。

という訳で、セッション内容を張っておきます。
今回はMockitoというFlexのモッキングフレームワークについて話しています。

広告

Posted in program | タグ: , , , , | Leave a Comment »

Mockito-Flexを利用してFlexのTDD/BDD環境を構築する(その2)

Posted by hikaruworld : 2011 2月 16

前回の続きになります。

Mockito-Flexの使い方

Java版のMockitoとの差異

基本的にはJava版のMockitoとほぼ同じですが、メソッドなど異なる部分もあります。
Java版のMockitoでは振る舞いのエミュレートの部分では、
when().thenを利用していましたが、mockito-flexの場合は、
given().willを利用する事になります。BDDMockito側を実装しているようですね。

ちょっとつらいのは、現在のmockitoでは複数の振る舞いの定義が出来ていないため、
以下のようなmockを書いても

given(hoge.piyo()).willReturn(“a”);
given(hoge.piyo()).willReturn(“b”);
given(hoge.piyo()).willReturn(“c”);

実行すると、以下のようになってしまいます。

trace(hoge.piyo()) // “a”
trace(hoge.piyo()) // “a”
trace(hoge.piyo()) // “a”

これは、Mockit-flex側でもIssuesとして、
#17 Multiple called given(something).willReturn(something) always returns first setted value
があがっていますが、まだ対応がはいっていないようです。
一応Answerを利用したやり方はあるようですので後述します。

Java版と同様な部分としては、DSL的な記述が可能なように
org.mockito.integrations以下にメソッド群が切り出されています。
Flex版ではグローバルメソッドとして定義されており、
Javaのようなstaticインポートが不要なところは言語的に楽ですね。

なお、これらのメソッドは実際はorg.mockito.Mockitoの
フィールドを呼び出すようになっています。
実際の挙動を確認する場合は、Mockitoの中身を確認すると良いかと思います。

Mockitoによる実装

ここからmockitoによって提供されている機能を確認していきます。
その際テスト対象のクラスが必要になりますので、
以下のクラスを対象にテストを行います。

public class Main
{
    public function Main()
    {
    }
    public function say(name:String):String
    {
        return "Hi " + name;
    }
    public function say(name:String):String
    {
        return "Hi " + name;
    }
    public function sayObj(obj:Object):String
    {
        return "obj is " + name;
    }
    public function check(data:Data):String
    {
        return data.userId;
    }
}
public class Data
{
	public var userId:int;
	public function Data()
	{
	}
}

なお、前回の方法でtargetに格納されている事とします。

Mock化

任意のクラスをMock化して振る舞いを設定する場合の方法です。

givenによる振る舞いの設定

given()を利用する場合は、以下のように記述します。

given(mock化するメソッドとその引数).willReturn(戻り値)

givenの引数にはmock化するメソッド[Mock]対象と、エミュレートしたい引数を設定します。
この引数はmockitoが提供するメソッドを利用して柔軟に設定する事が可能です。
willReturnはgivenによって与えられた条件時に返す値を定義します。
willReturn以外にも、will,willThrowがあります(詳しくは後述)。

引数のmock化

given時に引数をmock化するためのメソッドを見ていきます。

any()

any()は引数にどんな値を与えられても良い事を表します
(当然引数で定義される型の範囲内でですが)。
なお、any()はnull値を許容しますので、値がnullの場合でもmockとして処理されます

/**
 * anyのテストケースを検証_NULLでない場合
 */
[Test]
public function any_is_not_null():void
{
	given(target.say(any())).willReturn("piyo");
	
	var result:String = target.say("abc");
	
	assertThat(result, isA("piyo"));
}
/**
 * anyのテストケースを検証_NULLの場合
 */
[Test]
public function any_is_null():void
{
	given(target.say(any())).willReturn("piyo");

	// nullの場合でもwillReturnの値が返される
	// ちなみにundefでも問題なし
	var result:String = target.say(null);
	
	assertThat(result, isA("piyo"));
}

anyOf(Class)

anyOfも引数にどんな値を与えられても良い事を表します。
anyOfの引数には、対象の型を指定します。
例えばStringの場合は、anyOf(String)のように引数の型を指定します。

/**
 * anyOfのテストケースを検証_NULLでない場合
 */
[Test]
public function anyOf_is_not_null():void
{
	given(target.say(anyOf(String))).willReturn("piyo");

	var result:String = target.say("abc");

	assertThat(result, isA("piyo"));
}

ただし、前述のany()と異なりnull値を許容しません。mock化したメソッドに対して、
nullを引数に呼ばれた場合はArgumentErrorがthrowされます。

ArgumentError: obj cannot be null

havingPropertyOf

havingPropertyOf(property, value)は引数の持つプロパティの値が一致する場合に、
実行することが可能です。

[Test]
public function havingPropertyOf_test():void
{
        // 引数に渡されたプロパティuserIdが12の場合だけmock処理を行うように設定
	given(target.check(havingPropertyOf("userId", 12))).willReturn(22);

	var data:Data = new Data();
	data.userId = 12;
        // この場合にはwillReturnで指定した22が結果としてかえる。
	var result:int = target.check(data);

	verify().that(target.check(data));
	assertThat(result, isA(22));
}

TODO 継承周りとか調査

isItNaN

これはNaNつまり非数である場合にのみMock処理を行うために利用されます

[Test]
public function isItNaN_test():void
{
	given(target.sayObj(isItNaN())).willReturn("NaN value");

	var result:String = target.sayObj(Number.NaN);

	assertThat(result, isA("NaN value"));
}

notNull

そのまんまですね。値がnullでない場合のみMockのエミュレーションが実行されます。

[Test]
public function notNull_test():void
{
	given(target.say(notNull())).willReturn("Value is Null");

	var result:String = target.say("hoge");

	assertThat(result, isA("Value is Null"));
}

と、今回はこの辺で。
次回はverify周りに付いて書きます。

Posted in program | タグ: , , , , | Leave a Comment »

Mockito-Flexを利用してFlexのTDD/BDD環境を構築する(その1)

Posted by hikaruworld : 2011 2月 14

FlexでもユニットテストやMockライブラリが充実し、ずいぶんテストがしやすくなっています。
そこで、FlexでTDD/BDD環境の構築をしてみます。
なお、環境は以下のように構築しています

IDE FlashBuilderBurittoPreview
TestingFramework FlexUnit4 / Hamcrest-as / Mockito-Flex

Mockito-FlexはMock処理を簡単に行うためのフレームワークです。
内部的な実装はASMockに依存していますが、Mockitoを利用することで
ASMockのRecord->Replayの処理を省いて簡単にMockが作れるようになります(なるはず…)。

ライブラリの入手

必要な物を一通りダウンロードしてlibs以下においてパスを通します。

mockito-flex

今回の話題となるMockito-Flexです。
ここから現在の最新版1.4M5をダウンロードします。

FlexUnit4

FlashBuilder4にもFlexUnit4は同梱されているのですが、
ちょっと古いらしくRuleの実装がはいっていないバージョンです。
mockito-flexを利用する際、[Rule]があると楽できるため、ここから最新を落としておきます。
ちなみにバージョンは、FlexUnit4.1RC2でした。

Hamcrest-AS3

どうせなのでHamcrestのバージョンも最新にしておきましょう。
Hamcrest-as3はgitHubのここにあります。現時点での最新のバージョンは1.1.3になります。

テストうんぬん前にまずやるべき事

mockitoは最新版はAPIドキュメントなどもないので、ソースをダウンロードしておきます。
ソースはswcに紐つけておきましょう。
(Referenced Libraries -> mockito.XXX.swc -> 右クリックしてプロパティ -> ソース添付 -> 編集)
あと忘れずに、ASDocを作っておきます(以下はコマンドラインから)。

$ pwd
mockito-flex/mockito/src
$ asdoc -source-path ./main/flex/ -doc-sources ./main/flex/ -library-path ../libs/

まだドキュメントが十分そろっていないようですし、分からなくなったらASDocとソースを見るのが解決に一番の近道です。

テストのやりかた

さて、本題です。
ここにmockitoをFlexUnit4で動かすやり方が書いてありますので手順に従ってやっていきます。

基本的なやり方

mockitoをFlexUnit4上で利用するには3つの方法があるようです。

方法1:従来のケース

従来の方法?では、テストクラスへの[RunWith]を利用してmock化を行います。

/**
 * クラス宣言時にFlexUnit4の[RunWith]を利用してMockitoClassRunnerを指定
 */
[RunWith("org.mockito.integrations.flexunit4.MockitoClassRunner")]
public class MainTest
{
  /** Mock化対象のクラスを定義 */
  [Mock(type="com.wordpress.prepro.Main")]
  public var target:Main;
  
  // Testコード...
}

方法2:新しい方法(インスタンス化の制御を自信で行わない)

この方法を利用した場合、[Rule]の機能を利用してMockのインスタンス化が制御されます。
そのため、MockitoRuleを[Rule]メタタグを付けて初期化しておく必要があります。
ただし、インスタンス化の制御を[Rule]に依存するため、RunWithの設定を必要としません。

なお前述しましたが、Ruleは現在FBに同梱されているFlexUnitには含まれていません
ライブラリの部分の手順に従って、事前に最新版に置き換えておく必要があります。

/** [RunWith]は不要 */
public class MainTest
{
  /**
   * [Rule]でMockitoRuleをインスタンス化
   */
  [Rule]
  public var mockitoRule:IMethodRule = new MockitoRule();

  /**
   * Mock化対象クラスの宣言
   * 必ず***public***である必要がある。
   */
  [Mock(type="com.wordpress.prepro.Main")]
  public var mockie:Main;
  
  // Testコード...
}

なお、Mock化したいクラスにコンストラクタ引数が存在する場合は、以下のように設定します。
こうする事で、Mainクラスに引数1がコンストラクタ引数として渡されます。

/**
 * typeでMock化したいクラスを指定
 * argsListでコンストラクタに渡す値をもつフィールドを指定します
 */
[Mock(type="com.wordpress.prepro.Main", argsList="args")]
public var target:Main;
/**
 * Mock化するクラスに渡す引数を配列形式で定義します。
 */
public var args:Array = [1];

※ただし、この方法はドキュメント上には見つかりませんでした。
テストコードで見つけたので、今後どうなるかは不明です。

方法3:新しい方法2(インスタンス化の制御を自力で制御する)

方法2ではテスト実行時にmockオブジェクトが初期化※0されますが、
この方法を用いるとmock()メソッドを利用してmockオブジェクトのインスタンス化を制御します。

/**
 * Mock化対象クラスの宣言
 */
[Mock(type="com.wordpress.prepro.Main")]
public class MainTest
{
  /**
   * [Rule]でMockitoRuleをインスタンス化
   */
  [Rule]
  public var mockitoRule:IMethodRule = new MockitoRule();

  public var target:Main;
  
  // テストコード
  [Test]
  public function test():void
  {
    // mock()でmock化
    this.target = mock(Main);
  }
}

この方法のメリットは好きなときにmock化を制御できること、
また、その際にコンストラクタ引数を任意に指定できる事だと思います。

/**
 * Constructs mock object
 * @param clazz a class of the mock object
 * @param name a name used in various output
 * @param constructorArgs constructor arguments required to create mock instance
 * @return a mocked object
 */
function mock(clazz:Class, name:String=null, constructorArgs:Array=null):*;

とあるように、第一引数にMock化したいクラス名、第二引数にエイリアス?、
第三引数にコンストラクタ引数を指定する事が出来ます。

方法2のフィールド指定によるMock化では、コンストラクタ引数をプロパティとして、
定義しておく必要がありますが、方法3では、テストメソッド内でMockを組み立てながら、
引数を考える事が出来ます。

なお、不適切な引数の状態でMock化を指定した場合、
初期化時に以下のエラーが発生してしまいます。

ArgumentError: Incorrect number of constructor arguments supplied.

※0具体的には[Test]の実行時単位で初期化されます。

設定を間違った場合(タイポや、privateフィールドにしていたetc)などはmockオブジェクトの初期化に失敗するため、
nullアクセスのエラーが以下のようにメッセージ出力されます。
今のFlashBuilderだとカスタムメタデータまでは補完してくれないので、タイポに気をつけましょう….

TypeError: Error #1009: Cannot access a property or method of a null object reference.

何だか長くなってしまったので次に続きます。
次は、実際にmockやverifyを利用して[Test]を実行していきます。

Posted in program | タグ: , , , , | Leave a Comment »