前回の続きになります。
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周りに付いて書きます。