Mockitoは、Javaで人気のあるMocking frameworkです。 MockitoでオブジェクトをmockingてUnit Testを作成できます。
直接Mockオブジェクトを作成することができますがMockitoと同じMocking frameworkを使用すると、面倒なコードを書く必要がなくなります。
この記事では、Mockitoにどのようにテストコードを作成するかを知ってみましょう。
- Mocking
- Verify
- ArgumentCaptor
- Spying
- Exception足
依存性の設定
gradleプロジェクトでは、次のように依存性を設定すると、JUnitとMockitoライブラリを使用することができます。
dependencies {
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.7.22'
}
Mocking
次のように mock(ClassToMock.class)
でMockオブジェクトを作成することができます。
Mockオブジェクトを作成すると、内部のコードはすべて動作しておらず、戻り値は0、false、nullなどで置き換えられます。
@Test
public void mockingList() {
List mockList = mock(ArrayList.class);
mockList.add("apple");
assertEquals("apple", mockList.get(0));
}
上記のコードを実行してみると、nullが返され、テストが失敗します。
java.lang.AssertionError:
Expected :apple
Actual :null
When
when
を使用すると、どのような状況ではMockオブジェクトがどのような値を返すようにすることができます。
これStubbing呼ばれます。
次のコードを解釈すると mockList
オブジェクトがget(0)
を呼び出すときに、"appple"
を返しなさいということです。
when(mockList.get(0)).thenReturn("apple");
次のように get()
、 size()
が呼び出されると、特定の値が設定されるようにしました。
@Test
public void mockingList_when() {
List mockList = mock(ArrayList.class);
when(mockList.get(0)).thenReturn("apple");
when(mockList.get(1)).thenReturn("kiwi");
when(mockList.size()).thenReturn(10);
assertEquals("apple", mockList.get(0));
assertEquals("kiwi", mockList.get(1));
assertEquals(10, mockList.size());
}
入力された引数とは無関係に特定の値を返すしたい場合は anyInt()
を使用します。
このほか、 anyString()
、 anyLong()
など、すべてのタイプのメソッドが提供されます。
@Test
public void mockingList_when2() {
List mockList = mock(ArrayList.class);
when(mockList.get(anyInt())).thenReturn("apple");
assertEquals("apple", mockList.get(0));
assertEquals("apple", mockList.get(1));
}
Verify
verify
を利用すれば、mockオブジェクトにどのようなAPIが呼び出されたか、何度呼び出したことを確認することができます。
次のコードは、 mockList.add("apple")
が呼び出されたことを確認します。もし呼び出されていない場合、テストは失敗します。
verify(mockList).add("apple");
次のコードは、 mockList.get(0)
が二度呼び出されたことを確認します。 times()
の引数に予想される呼び出し回数を転送します。
verify(mockList, times(2)).get(0);
だから、次のようにメソッドが呼び出されたかを確認することができます。
atLeastOnce()
、 atLeast()
、 times()
などのメソッドを提供してくれ何度呼び出していることを確認することができます。
@Test
public void mockingList_verify() {
List mockList = mock(ArrayList.class);
mockList.add("apple");
verify(mockList).add("apple");
mockList.get(0);
mockList.get(0);
verify(mockList, times(2)).get(0);
verify(mockList, atLeast(2)).get(0);
}
ArgumentCaptor
ArgumentCaptorはMockオブジェクトに渡された引数を確認する目的で使用します。
次のコードは、 mockList.add()
の引数を読み込むコードです。 verifyに capture()
を渡して getValue()
でどんな値が渡されていることを確認することができます。
ArgumentCaptor<String> arg = ArgumentCaptor.forClass(String.class);
verify(mockList).add(arg.capture());
assertEquals("apple", arg.getValue());
次のようにArgumentCaptorを利用して、 add()
のいくつかの因子が配信された確認できます。
@Test
public void captorExample() {
ArgumentCaptor<String> arg = ArgumentCaptor.forClass(String.class);
mockList.add("apple");
verify(mockList).add(arg.capture());
assertEquals("apple", arg.getValue());
}
Spying
Mockオブジェクトは、内部実装が動作せず0、false、nullなどが返されるとしたんです。 Spyオブジェクトは、実際のオブジェクトのように動作し、verifyにどのメソッドが呼び出されたかを確認することができます。 また、whenキーワードで、いくつかのメソッドをstubbingすることができます。
次のようにspyオブジェクトを作成することができます。実行してみると、テストはpassており、実際のオブジェクトのように動作することがわかります。
@Test
public void spyingList() {
List spyList = spy(ArrayList.class);
spyList.add("apple");
assertEquals("apple", spyList.get(0));
}
次のように verify
でメソッドが呼び出された検証することができます。
@Test
public void spyingList_verify() {
List spyList = spy(ArrayList.class);
spyList.add("apple");
verify(spyList).add("apple");
spyList.get(0);
verify(spyList).get(0);
}
さらに、次のように when
に、いくつかのメソッドをstubbingすることができます。しかし、次のコードは、問題があります。
@Test
public void spyingList_when_error() {
List spyList = spy(ArrayList.class);
when(spyList.get(0)).thenReturn("apple");
when(spyList.get(1)).thenReturn("kiwi");
when(spyList.size()).thenReturn(10);
assertEquals("apple", spyList.get(0));
assertEquals("kiwi", spyList.get(1));
assertEquals(10, spyList.size());
}
上記のコードを実行すると、 IndexOutOfBoundsException
例外が発生し、テストは失敗します。
spyオブジェクトは実際のオブジェクトのように動作するので、 when
コードでspyList.get(0)
を呼び出すときにItemがなくExceptionが発生する可能性があります。
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:659)
at java.util.ArrayList.get(ArrayList.java:435)
こういうときは、 doReturn().when()
のパターンに変更してくれれば、正常にstubbingすることができます。
@Test
public void spyingList_when_ok() {
List spyList = spy(ArrayList.class);
doReturn("apple").when(spyList).get(0);
doReturn("kiwi").when(spyList).get(1);
doReturn(10).when(spyList).size();
assertEquals("apple", spyList.get(0));
assertEquals("kiwi", spyList.get(1));
assertEquals(10, spyList.size());
}
したがって、spyオブジェクトをstubbingするとき when().thenReturn()
パターンを使用せずに
doReturn().when()
パターンを使用することをお勧めします。
Exception発生
特定の状況でExceptionが発生することがあります。
when().thenThrow(ExceptionClass)
パターンを使用します。
@Test
public void whenGetUserInfo_throwException() {
Contacts contactsMock= mock(Contacts.class);
when(contactsMock.getUserInfo(anyInt()))
.thenThrow(NullPointerException.class);
contactsMock.getUserInfo(0);
}
thenThrow()
の引数としてクラス名を渡すことなく、 new NullPointerException(msg)
のようにExceptionオブジェクトを生成して転送することもできます。
@Test
public void whenGetUserInfo_throwExceptionWithMsg() {
Contacts contactsMock= mock(Contacts.class);
when(contactsMock.getUserInfo(anyInt()))
.thenThrow(new NullPointerException("Null pointer exception happened"));
contactsMock.getUserInfo(0);
}
上記のコードを実行すると、Exceptionが発生し、テストは失敗します。 Exceptionが発生することを確認したので、テストはパスする必要があります。
次のように、NullPointerExceptionが発生しない場合、テストは失敗し、Exceptionが発生した場合、成功するように実装することができます。
@Test
public void whenGetUserInfo_throwException2() {
Contacts contactsMock= mock(Contacts.class);
when(contactsMock.getUserInfo(anyInt()))
.thenThrow(NullPointerException.class);
try {
contactsMock.getUserInfo(0);
fail();
} catch (NullPointerException e) {
// pass
}
}
より簡単で、可読性が良い方法は、 @Test
に次のように例外が発生すると明示することです。
もしExceptionが発生した場合、テストは成功しており、それ以外の場合、テストは失敗します。
@Test(expected = NullPointerException.class)
public void whenGetUserInfo_throwException3() {
Contacts contactsMock= mock(Contacts.class);
when(contactsMock.getUserInfo(anyInt()))
.thenThrow(NullPointerException.class);
contactsMock.getUserInfo(0);
}
Void-Return Typeメソッドで例外が発生
Voidに設定されたメソッドは、次のように doThrow().when()
パターンでExceptionが発生するように実装する必要があります。
@Test(expected = NullPointerException.class)
public void whenCallsVoidReturnTypeMethod_throwException() {
Contacts contactsMock= mock(Contacts.class);
doThrow(NullPointerException.class)
.when(contactsMock)
.addUserInfo(anyString(), anyString());
contactsMock.addUserInfo("AAA", "123-456");
}
spyオブジェクトで例外が発生
次のようにSpyオブジェクトもMockと同じように、Exceptionを発生させることができます。
@Test(expected = NullPointerException.class)
public void whenGetUserInfo_throwException4() {
Contacts contactsMock= spy(Contacts.class);
when(contactsMock.getUserInfo(anyInt()))
.thenThrow(NullPointerException.class);
contactsMock.getUserInfo(0);
}
まとめ
Mockitoライブラリを使用してMockとSpyオブジェクトを作成しverifyで検証する方法を説明しました。 また、whenにstubbingして、特定の値を返すか、例外を発生させるようにする方法を説明しました。
Related Posts
- Java - AtomicReference使用方法
- Java - CountDownLatchを使用する方法、および例
- Java - ScheduledThreadPoolExecutor使用方法
- Java - SummaryStatisticsの使用方法(count、min、max、average)
- Java8 - 関数型インタフェース (Functional Interface) について
- Java - String配列をint配列に変換する
- Java - ArrayList要素の値を変更する方法、replaceAll()
- Java - 2つのリストが同じかどうかを比較
- Java - 配列から特定のIndex要素を削除する3つの方法
- Java - HashMapソート、4つの方法
- Java - 文字列を配列に変換する方法
- Java - ArrayListが空であることを確認する3つの方法
- Java - ArrayListの巡回、4つの方法
- Java - ArrayListの最大値、最小 値を見つける
- Java - ArrayListの合計、平均値の計算
- Java - HashMap巡回、3つの方法
- Java - do whileとwhileの違い
- Java - Lambda式と関数型インタフェース
- Java - List empty(null)チェック、3つの方法
- Java - ArrayListの初期化、4つの方法
- Java - Stream.reduce()の使い方と例
- Java - 2つのマップを結合する(merge、putAll)
- Java - java.util.Dateをjava.sql.Dateに変換する
- Java - ArrayListをStringに変換する
- Java - ClassNotFoundExceptionの発生原因と解決策
- Java - 非静的メソッドは静的コンテキストから参照できません
- Java - NoSuchMethodErrorの原因と解決策
- Java - JSONライブラリを使用する方法(JSONObject、JSONArray)
- Java - byte[]配列をFileに保存
- Java - byte[]の配列をStringに変換
- Java - ファイルのアクセス権を確認し、変更
- Java - 一時フォルダ(Temp directory)パスを取得する
- Javaでシェルスクリプトを実行
- Java - Streamを配列に変換する
- Java - リスト重複排除、2つの方法