Mockitoの使い方
<記事概要>
スタブとモックの違いについて記載した後、Javaのモック用のライブラリのMockitoの使い方を記載する。なお下記は記載対象外、リファレンスを参照。
・Mokitoのver3.4.0から対応のstaticメソッドのスタブ化
・verifyによる呼び出しメソッドの検証
Mokito3.7.7リファレンス
https://javadoc.io/static/org.mockito/mockito-core/3.7.7/org/mockito/Mockito.html
<動作環境>
Mokito:3.7.7
OS:Windows10
Eclipse:4.7.3
JDK:1.8.0
Junit:4.12.0
<スタブとモックの違いについて>
両者ともにモジュールの代替品であるが、使用目的が異なる。
スタブとは
スタブは予測可能な値を返すように仮実装されたモジュールの代替品。
以下のような場合にスタブが使われる。
・依存モジュールがランダム性の高い振る舞いをする。
・依存モジュールが単体テスト時にまだ存在しない。
・依存モジュールの実行コストが高く、簡単に利用できない。
・依存モジュールが実行環境に強く依存している
モックとは
モックは、テスト対象クラスが依存するモジュールが、正しく呼ばれているか検証するために使われるモジュールの代替品。
検証内容の例
・依存モジュールが何回呼ばれているか
・依存モジュールが正しい引数を渡されて呼ばれているか
Mokitoにおけるモックとスタブ
Mokitoではモックとスタブの明確な区別はない。
後述の@Mockアノテーションで作成されたモックは、すべてのメソッドがnull(プリミティブ型の場合はデフォルト値)を返すスタブメソッドとして初期設定されている。
メソッドの呼び出し検証を行うならモックオブジェクトといえるし、スタブメソッドを利用する目的ならスタブオブジェクトといえる。
サンプルソース
テスト対象クラス
package hoge.howtoMockito;
import java.util.Random;
public class Sample {
private Random ram;
public Sample() {
ram = new Random();
}
public int getRandomNum() {
return ram.nextInt(3);
}
}
テスト対象SampleクラスはRandomクラスに依存している。getRandomNum()メソッドは単体テストを実行する度に返却値が異なり、テストが難しい。Randomクラスをモック(スタブ)として用意し、getRandomNum()メソッドが乱数ではなく、固定値を返すようにする。
テストクラス
package hoge.howtoMockito;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;
import java.util.Random;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class SampleTest {
@Mock
private Random mockRandom;
@InjectMocks
private Sample sut;
@Before
public void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
public void getRandomNumは0を返す() {
doReturn(0).when(mockRandom).nextInt(3);
int actual = sut.getRandomNum();
int expected = 0;
assertThat(actual, is(expected));
}
@Test
public void getRandomNumは1を返す() {
doReturn(1).when(mockRandom).nextInt(3);
int actual = sut.getRandomNum();
int expected = 1;
assertThat(actual, is(expected));
}
@Test
public void getRandomNumは2を返す() {
doReturn(2).when(mockRandom).nextInt(3);
int actual = sut.getRandomNum();
int expected = 2;
assertThat(actual, is(expected));
}
}
①モックオブジェクトの作成
@Mockアノテーションでモック化したいオブジェクトを指定する。今回はRandomクラス。
②モックオブジェクトをインジェクトする
@InjectMocksアノテーションでモックオブジェクトのインジェクト先を指定する。今回はSampleクラス
③上記①、②のアノテーションを有効にする。
テストクラスの@Beforeか親クラスに下記を記載する。
MockitoAnnotations.openMocks(this);
※なお、最新APIによる下記の使用は非推奨とのこと
MockitoAnnotations.initMocks(this);
④スタブメソッドの設定
以下の形式でスタブメソッドを設定する。
「doReturn(スタブ値).when(モックオブジェクト).スタブ化したいメソッド」
下記のように記載すると、RandomクラスのnextInt(3)が呼ばれた時に固定値0を返す
「doReturn(0).when(mockRandom).nextInt(3);」
その他Mokitoでできることできないこと
できること
・staticメソッドのスタブ化
・verifyによるメソッド呼び出し回数の検証
・doThrowによるスタブメソッドの例外発生
・@spyアノテーションによる一部メソッドのスタブ化(スタブ化されなかったメソッドは実際の処理のまま)
・ArgumentCaptorによるスタブメソッドの引数検証
できないこと
・ローカル変数のモック化(スタブ化)
ローカル変数をモック化したい場合はPowerMockなるライブラリを使えばできるらしい・・・。