Deletions are marked like this. | Additions are marked like this. |
Line 9: | Line 9: |
== ふるまいを検証してみよう == | == 1.ふるまいを検証してみよう == |
Line 28: | Line 28: |
== スタブを作ってみよう == | == 2.スタブを作ってみよう == |
Line 57: | Line 57: |
== 引数の一致 == | == 3.引数の一致 == |
Line 99: | Line 99: |
== 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オブジェクトには、順序検証に関連するオブジェクトだけを与えればよい。 |
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オブジェクトには、順序検証に関連するオブジェクトだけを与えればよい。