Deletions are marked like this. | Additions are marked like this. |
Line 165: | Line 165: |
== 7. モックのメソッド呼び出しが無かったことを確認する == {{{ //モックを使う。mockOneのみが呼び出される。 mockOne.add("one"); //通常の検証 verify(mockOne).add("one"); //次の作用は一度も無かったことを検証 verify(mockOne, never()).add("two"); //他のモックは何の作用も無いことを検証 verifyZeroInteractions(mockTwo, mockThree); }}} == 8. 冗長な呼び出しを見つける == {{{ //モックを使う mockedList.add("one"); mockedList.add("two"); verify(mockedList).add("one"); //次の検証は失敗 verifyNoMoreInteractions(mockedList); }}} 注意:クラシックはexpect-run-verifyスタイルのモッキングを使っていたユーザは、すべてのテストメソッドでよくverifyNoMoreInteractions()を使いたがる。 しかし、verifyNoMoreInteractions()をすべてのテストメソッドで使うことは推奨されない。 verifyNoMoreInteractions() is a handy assertion from the interaction testing toolkit. Use it only when it's relevant. Abusing it leads to overspecified, less maintainable tests. You can find further reading here. never()を参照すること。こちらの方が明快だし意図がはっきりする。 == 9. モック生成のショートカット - @Mockアノテーション == * モック生成コードの繰り返しを避けることができる。 * テストクラスが読みやすくなる。 * 検証エラーが読みやすくなる。なぜなら、フィールド名によってモックを識別できるから。 {{{ public class ArticleManagerTest { @Mock private ArticleCalculator calculator; @Mock private ArticleDatabase database; @Mock private UserProvider userProvider; private ArticleManager manager; }}} 重要:以下がベースクラスか、あるいはテストランナーに必要である。 {{{ MockitoAnnotations.initMocks(testClass); }}} ビルトインランナーであるMockitoJUnitRunnerの使用を考慮すること。 [[http://mockito.googlecode.com/svn/tags/latest/javadoc/org/mockito/MockitoAnnotations.html|MockitoAnnotations]]を参照のこと。 |
mockitoマニュアル
以下はMockitoクラスJavaDocの訳(Version 1.8.1、現在翻訳進行中)
以下の例はListをモックしているが、これは誰もがそのインターフェース(add, get, clear等のメソッド)を知っているからだ。 たぶん、実際にはListをモックすることなんかないだろうけど。
1.ふるまいを検証してみよう
//Mockitoをstatic importすると、コードがきれいに書けるよ import static org.mockito.Mockito.*; //モックを作る List mockedList = mock(List.class); //モックオブジェクトを使ってみる mockedList.add("one"); mockedList.clear(); //検証する verify(mockedList).add("one"); verify(mockedList).clear();
モックはすべての作用を記録している。後で興味のある作用についてだけ検証することができる。
2.スタブを作ってみよう
//コンクリートクラスのモックを作成することができる、インターフェースだけじゃなく LinkedList mockedList = mock(LinkedList.class); //スタブ化 when(mockedList.get(0)).thenReturn("first"); when(mockedList.get(1)).thenThrow(new RuntimeException()); //以下は"first"を表示する System.out.println(mockedList.get(0)); //以下は実行時例外を投げる System.out.println(mockedList.get(1)); //以下は"null"を表示する、get(999)はスタブされていないから。 System.out.println(mockedList.get(999)); //スタブを検証することもできるけれども、冗長だろう。 //If your code cares what get(0) returns then something else breaks (often before even verify() gets executed). //If your code doesn't care what get(0) returns then it should not be stubbed. Not convinced? See here. verify(mockedList).get(0);
- デフォルトでは、すべての返り値のあるメソッドについては、モックはnull, 空のコレクション、適当なプリミティブやプリミティブラッパ値(例えば、0, false, ...)などを返す。
- スタブ化はオーバライドできる。例えば、共通のスタブ化をfixtureセットアップで行い、テストメソッド中でオーバライドする。ただ、スタブ化のオーバライドは「スタブしすぎ」の匂いも漂う。
- 一度スタブ化されると、何度呼び出されようが、同じ値を返す。
- 同じメソッドを同じ引数でスタブ化した場合、最後のスタブ化だけが生き残る。
3.引数の一致
Mockitoは引数が一致するかどうかを通常のJavaスタイルでチェックする。つまり、equals()メソッドを使う。しかし、もっとフレキシブルな方法が必要になることもある。その場合はmatcher引数を使うことができる。
//(Mockitoに)付属のanyInt()matcherを使ってスタブ化 when(mockedList.get(anyInt())).thenReturn("element"); //hamcrestを使ってスタブ化。ここではisValid()メソッドが、あなたの作成したhamcrest-matcherを返すものとする。 when(mockedList.contains(argThat(isValid()))).thenReturn("element"); //以下は"element"を表示する System.out.println(mockedList.get(999)); //引数matcherを使って検証することもできる。 verify(mockedList).get(anyInt());
引数matcherによってフレキシブルな検証とスタブ化をすることができる。 ここ にビルトインmatcher、カスタム引数matcher、hamcrest-matcherの情報がある。
カスタム引数matcherについてはArgumentMatcherを参照のこと。
複雑な引数マッチングについて妥当性を保つこと。 The natural matching style using equals() with occasional anyX() matchers tend to give clean & simple tests. equals()によるマッチングを許すように、あるいはequals()を実装するようにコードをリファクタリングした方が良い場合もある。
また、セクション15あるいはArgumentCaptorを読むこと。ArgumentCaptorは後のアサーションのために、引数値をキャプチャする特別な引数matcherである。
引数matcherに関する注意:
引数matcherを使う場合は、すべての引数がmatcherで提供されなければならない。
例: (この例は検証のみだが、スタブ化でも同様):
verify(mock).someMethod(anyInt(), anyString(), eq("third argument")); //上は正しい。eq()も引数matcherである verify(mock).someMethod(anyInt(), anyString(), "third argument"); //上は不正。なぜなら、三番目の引数は引数matcherとして提供されていない。
4. 正確な呼び出し数を検証する。at least x / never
//モックを使う mockedList.add("once"); mockedList.add("twice"); mockedList.add("twice"); mockedList.add("three times"); mockedList.add("three times"); mockedList.add("three times"); //次の二つの検証は全く同じ。デフォルトでは、times(1)が適用される。 verify(mockedList).add("once"); verify(mockedList, times(1)).add("once"); //正確な呼び出し数を検証する。 verify(mockedList, times(2)).add("twice"); verify(mockedList, times(3)).add("three times"); //never()を使う。never()はtimes(0)の別名である。 verify(mockedList, never()).add("never happened"); //atLeast()/atMost()を使った検証 verify(mockedList, atLeastOnce()).add("three times"); verify(mockedList, atLeast(2)).add("five times"); verify(mockedList, atMost(5)).add("three times");
times(1)はデフォルトなので、これを省略することができる。
5. voidメソッドの例外スタブ化
doThrow(new RuntimeException()).when(mockedList).clear(); //以下はRuntimeExceptionを投げる mockedList.clear();
パラグラフ12のdoThrow|doAnswerファミリーを参照のこと。
初期バージョンでは、stubVoid(Object)をvoidメソッドのスタブ化に使用していた。 現在ではstubVoid()はdeprecatedとなっており、代わりにdoThrow(Throwable)を用いる。 この理由はリーダビリティの改善とdoAnswer(Answer)メソッドファミリーとの一貫性のためである。
6. 順序の検証
List firstMock = mock(List.class); List secondMock = mock(List.class); //モックを使う firstMock.add("was called first"); secondMock.add("was called second"); //順序検証が必要なモックを与えてinOrderオブジェクトを作成する InOrder inOrder = inOrder(firstMock, secondMock); //以下では、firstMock, secondMockの順で呼ばれることを検証する。 inOrder.verify(firstMock).add("was called first"); inOrder.verify(secondMock).add("was called second");
順序検証はフレキシブルに作られている。すべての作用(メソッド呼び出し)を一つ一つ検証する必要はなく、必要なものだけを検証すればよい。
また、InOrderオブジェクトには、順序検証に関連するオブジェクトだけを与えればよい。
7. モックのメソッド呼び出しが無かったことを確認する
//モックを使う。mockOneのみが呼び出される。 mockOne.add("one"); //通常の検証 verify(mockOne).add("one"); //次の作用は一度も無かったことを検証 verify(mockOne, never()).add("two"); //他のモックは何の作用も無いことを検証 verifyZeroInteractions(mockTwo, mockThree);
8. 冗長な呼び出しを見つける
//モックを使う mockedList.add("one"); mockedList.add("two"); verify(mockedList).add("one"); //次の検証は失敗 verifyNoMoreInteractions(mockedList);
注意:クラシックはexpect-run-verifyスタイルのモッキングを使っていたユーザは、すべてのテストメソッドでよくverifyNoMoreInteractions()を使いたがる。 しかし、verifyNoMoreInteractions()をすべてのテストメソッドで使うことは推奨されない。
verifyNoMoreInteractions() is a handy assertion from the interaction testing toolkit. Use it only when it's relevant. Abusing it leads to overspecified, less maintainable tests. You can find further reading here.
never()を参照すること。こちらの方が明快だし意図がはっきりする。
9. モック生成のショートカット - @Mockアノテーション
- モック生成コードの繰り返しを避けることができる。
- テストクラスが読みやすくなる。
- 検証エラーが読みやすくなる。なぜなら、フィールド名によってモックを識別できるから。
public class ArticleManagerTest { @Mock private ArticleCalculator calculator; @Mock private ArticleDatabase database; @Mock private UserProvider userProvider; private ArticleManager manager;
重要:以下がベースクラスか、あるいはテストランナーに必要である。
MockitoAnnotations.initMocks(testClass);
ビルトインランナーであるMockitoJUnitRunnerの使用を考慮すること。 MockitoAnnotationsを参照のこと。