このエントリーをはてなブックマークに追加

mockito

mockitoとは

 MockitoとはJavaでユニットテスト(Junit)を行う際に簡単にモックオブジェクトを作成し適用することができるモックフレームワークです。
簡単にモックオブジェクトを作成することができるため、試験を行いたい処理を明確にし注力することできるようになります。
 MockitoはメソッドをMock化し、挙動を変更する事ができます。
例えばメソッドAからDBにアクセスし取得した結果を戻すメソッドBを呼び出し、他の処理を行うケースを想定してみます。
モックをつかない場合メソッドAの処理を製造し、試験を実施する場合にはメソッドBが製造・試験されておりかつDBが準備されている必要があります。
またメソッドBの戻り値によってメソッドAの挙動が変わる場合にはその分メソッドBの戻り値を準備してやる必要がありますが、どうデータを作成するのかなどメソッドBの動きを確認しながらデータの作成をすることになってしまいます。
本来メソッドAの挙動を試験したいはずなのに、メソッドBの動きを確認するなど予想外に時間がかかってしまいメソッドAの試験に注力することができなくなってしまいます。それでは本末転倒です。
そこでモックを使用するします。
モックを使用する場合、メソッドBのメソッド名、引数、戻り値が決まっていれば、戻り値を自由に変更することができます。
公式サイト

  https://site.mockito.org/

セットアップ

<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.10.19</version>
    <scope>test</scope>
</dependency>

基本的な使い方

Mockitoの基本的な使い方はJunit等のテスティングフレームワークと組み合わせて利用します。
基本的な構成としては
  1. Mock化する
  2. 振る舞いを記憶する
  3. 対象の処理を実行する
  4. 結果を検証する
となります。
1,2,4についてはMockitoを用いて作業を実施します。
各処理ごとに方法を見て行きたいと思います。
今回はサンプルとしてListクラスをMock化しながら動作を確認していきます。
(※ Mockito をスタティックインポートしておきます。)

1. Mock化する

まず最初に対象のクラスをMock化するための準備が必要になります。
Mock化する方法は以下の2つの方法でMock化することができます

(1)対象クラスをMock化し、インスタンスを作成する

対象のクラスをすべてMock化する方法になります。
対象のメソッドをmockメソッドの引数として渡す形になります。
この方法でMock化したクラスは振る舞いを登録しないメソッドには何も処理が行われません
List<String> mockList = mock(List.class);

(2)対象インスタンスをMock化する

 対象のクラスのインスタンスをMock化する方法になります。
対象のメソッドをspyメソッドの引数として渡す形になります。
この方法でMock化したオブジェクトは振る舞いを記録しないメソッドは元のメソッドの振る舞いが行われるため一部をMock化するようなケースで使用します。
List<String> mockList = new ArrayList<String>();
mockList = spy(mockList);
これ以降の作業については1,2のどちらでMock対象化していても特に影響はありません。

2. 振る舞いを記憶する

 Mock化したインスタンスのメソッドに対して振る舞いを記憶させます。
戻り値を設定するケース、例外が発生するように設定するケースなどがあります。
また戻り値が無いメソッドの場合異なる方法で振る舞いを設定させます。

(1)戻り値を設定するケース

 whenメソッド+thenReturnを組み合わせて振る舞いを記憶します。
まずwhenメソッドの引数に振る舞いを記憶するメソッドを設定します。この際に設定する引数もそのまま設定します。 その後thenReturnメソッドの引数に戻り値を設定します。以下にサンプルを示します。
// getメソッドに引数 0の場合 testValueという値を戻すように振る舞いを記憶させる
when(mockList.get(0)).thenReturn("testValue");

(2)例外を設定するケース

 whenメソッド+thenThrowを組み合わせて振る舞いを記憶します。
whenメソッドの引数に振る舞いを記憶するメソッドを設定します。この際に設定する引数もそのまま設定します。 その後thenThrowメソッドに発生させる例外をを設定します。以下にサンプルを示します。
// getメソッドに引数 0の場合 RuntimeExceptionがthrowされるように設定
when(mockList.get(0)).thenThrow(new RuntimeException("ランタイムException"));

(3)voidメソッドに振る舞いを設定するケース(通常)

 voidメソッドに振る舞いを設定する場合にはdoXXXメソッドを使用し、振る舞いを設定します。
何も挙動を設定せず実際のメソッドを呼ばれないようにするにはdoNothingをメソッド+whenメソッド+対象のメソッドを組み合わせて振舞いを設定します。
// clearメソッドに振る舞いを追加 doNothingメソッドは何もしない
doNothing().when(mockList).clear();

(4)voidメソッドに振る舞いを設定するケース(例外)

voidメソッドに振る舞いを設定する場合にはdoXXXメソッドを使用し、振る舞いを設定します。
例外を発生させるためにはdoThrowメソッド+whenメソッド+対象のメソッドを組み合わせて振舞いを設定します。
// clearメソッドに振る舞いを追加 doThrowメソッドで例外を振る舞いに登録する
doThrow(new RuntimeException("ランタイムException")).when(mockList).clear();

3. 対象の処理を実行する

対象の処理を実行するには通常通りにメソッドを呼び出すだけで使用することできます。
mockList.get(0);
や、
mockList.clear();
など通常通りのメソッド呼び出しで問題ありません。

4. 結果を検証する

 実際にMock化したメソッドが使用されているか確認します。利用シーンとしては対象のメソッドが呼び出されているかその際にどんな引数で呼び出されているかなどを使用するケースなどの場面で利用します。
verifyメソッドでは引数に対象のインスタンスを設定します。オーバーロードで第二2引数に呼び出された回数または処理時間のtimeout時間を設定し確認することもできます。
// 呼び出されているか確認する
verify(mockList).get(0);
// 1回 呼び出されているか確認する
verify(mockList, times(1)).get(0);
// 100msec中に呼び出されているか確認する
verify(mockList, timeout(100)).get(0);

上記のステップを踏むことで対象のメソッドをMock化し振る舞いを登録することができます。