Locked History Actions

Diff for "mockito/Manual"

Differences between revisions 4 and 5
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オブジェクトには、順序検証に関連するオブジェクトだけを与えればよい。