Mockitoとは?
Mockito
Mockito(モキート)は、JavaテストでMock(モック)オブジェクトを簡単に作成、管理、検証できる方法を提供するフレームワークである。
Mockはテスト用の偽物オブジェクトである。Mockitoでは、指定クラスのMockを作成し、任意のメソッドをstubとして指定値を返すようにしたり、Mockのメソッドが期待どおりに呼び出されたかを検証したりできる。Mock動作を型安全に定義できる点が大きな特徴である。
HelloWorld
Mockitoを使うには、たとえばorg.mockito:mockito-coreをテスト依存関係に追加する。そしてmock()でMockオブジェクトを作成し、when(...).thenReturn(...)で動作を定義する。
List<String> mock = mock(List.class);
when(mock.get(0)).thenReturn("Hello Mockito!");
ここではjava.util.ListのMockを作成し、get(0)を実行すると"Hello Mockito!"を返すように定義している。
Mockの基本動作
stubされていないMockメソッドはデフォルト値を返す。プリミティブ値はゼロ相当、コレクションは空コレクション、オブジェクト参照は一般的にnullを返す。
whenでStubを作る
Mockメソッドが返す値は次の形式で指定できる。
when(<stubにしたいメソッド呼び出し>).thenReturn(<メソッド戻り値>)
一度stub化されたメソッドは、別のstubで上書きしない限り常に同じ値を返す。
呼び出しごとに異なる値を返す
可変長引数のthenReturn(T...)を使うと、呼び出しごとに異なる値を返せる。指定数以上に呼び出された場合は、最後に指定した値が返され続ける。
例外を発生させる
thenThrow(Throwable...)を使うと、stubが例外を投げるようにできる。可変長引数を使えば、呼び出しごとに異なる例外を発生させられ、指定した例外が尽きると最後の例外が投げ続けられる。
戻り値と例外の組み合わせ
Mockitoでは、連続呼び出しに対して戻り値と例外を組み合わせることもできる。
任意の引数にマッチさせる
ArgumentMatchersのanyInt()、anyList()、any()などを使うと、任意の引数に対するstubを定義できる。
複数引数のメソッドで1つでもmatcherを使う場合、他のすべての引数もmatcherで指定する必要がある。特定値を指定したい場合はeq()を使う。
カスタム引数マッチング
組み込みmatcherだけでは足りない場合、カスタムmatcherを使用できる。
Stub内で任意処理を実行する
stubで任意の処理を実行したい場合はthenAnswer()を使う。MockitoにはAnswer1からAnswer6までの型付きヘルパーもある。ただし複雑なstubはテストの意味を分かりにくくし、保守性を下げるため乱用は避ける。公式文書でも可能な限りthenReturn()とthenThrow()を推奨している。
voidメソッドのstub
戻り値がvoidのメソッドで例外を発生させたい場合は、doThrow()から始まるstub化方法を使用する。
メソッドが呼び出されたか確認する
verify()を使うと、メソッドが呼び出されたかを確認できる。検証には引数も含まれる。
Mockitoでは次のことを検証できる。
- メソッドが一致する引数で呼び出されたか。
- メソッドが何回呼び出されたか。
- 少なくとも、または最大で指定回数呼び出されたか。
- 一度も呼び出されていないか。
InOrderによる呼び出し順序。- 複数Mockにまたがる呼び出し順序。
ArgumentCaptorによる実際に渡された引数。
Spy - スパイ
Spyは実オブジェクトを基に作成される。stubされていないSpyメソッドは実メソッドを実行する。Spyは元オブジェクトのコピーを基に作成されるため、Spyと元オブジェクトの変更が常に共有されるわけではない。
Spyをstub化するとき、when(spy.method())はstub定義時に実メソッドを呼び出すことがある。実メソッドを呼び出したくない場合はdoReturn().when(spy).method()を使う。実メソッドを実行せず例外を投げるstubにしたい場合はdoThrow()を使う。
Mockitoはspy(Class)で抽象クラスのSpyも作成できる。ただし対象クラスにはデフォルトコンストラクタが必要である。
他オブジェクトへの委譲
AdditionalAnswers.delegatesTo()を使うと、別オブジェクトへ呼び出しを委譲するMockまたはSpy風オブジェクトを作成できる。委譲先オブジェクトはMock対象型を継承している必要はない。
Serializable可能なMock
withSettings().serializable()を使うと、SerializableなMockを作成できる。
One-linerでMockとStubを作成
MockitoではMock作成とstub定義をコンパクトに1行で書ける。ただし、テストの可読性を保つため使いすぎには注意する。
アノテーションで定義する
Mockitoは@Mock、@Spy、@Captorなどのフィールドアノテーションをサポートする。Mockitoのアノテーション初期化機能で初期化する。JUnit 5ではmockito-junit-jupiterを追加してMockitoExtensionを使い、メソッド引数としてMockを受け取ることもできる。
inline mock maker
inline mock makerを導入すると、通常のMockitoではできないfinalクラスのMock化やstaticメソッドのstub化などが可能になる。依存関係にorg.mockito:mockito-inlineを追加する。
inline mock makerにより、次のことができる。
- finalクラスやfinalメソッドのMock/stub化。
Mockito.mockStatic(Class)によるstaticメソッドのstub化。mockConstruction()によるコンストラクタからのMock返却。
コンストラクタMockは、返されたMockedConstructionがcloseされるまで有効である。stubと検証は通常のMockito APIであるwhen()やverify()を使用する。
Mock化できないクラス定義
Mockitoには、Mock化すべきでないクラスを示す@DoNotMockがある。そのようなクラスをMock化しようとするとMockitoは失敗し、実インスタンスを作成するよう求める。