Mockitoとは?

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では、連続呼び出しに対して戻り値と例外を組み合わせることもできる。

任意の引数にマッチさせる

ArgumentMatchersanyInt()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は失敗し、実インスタンスを作成するよう求める。

参照