Revision 15 as of 2009-12-12 07:00:38

Clear message
Locked History Actions

mockito/Manual

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を参照のこと。

10. 連続呼び出しのスタブ化(イテレータスタイルスタブ)

同じメソッド呼び出しに対し、異なる値を返したり異なる例外を投げたりしたい場合がある。 その典型がイテレータのモッキングである。 Mockitoのオリジナルバージョンはこのような機能を持っていなかった。 例えば、Iteratorの代わりにIterableや単純なCollectionを使いたいことがある。 Those offer natural ways of stubbing (e.g. using real collections). しかし、稀だが連続呼び出しをスタブ化できた方が便利なこともある。

 when(mock.someMethod("some arg"))
   .thenThrow(new RuntimeException())
   .thenReturn("foo");
 
 //一度目の呼び出し。RuntimeExceptionを投げる
 mock.someMethod("some arg");
 
 //二度目の呼び出し。"foo"を表示
 System.out.println(mock.someMethod("some arg"));
 
 //引き続いての呼び出し。やはり"foo"を表示(最後のスタブ化が有効) 
 System.out.println(mock.someMethod("some arg"));

以下のようにも書ける。連続スタブ化の短いバージョンである。

 when(mock.someMethod("some arg"))
   .thenReturn("one", "two", "three");

11. コールバックのスタブ化

Answerインターフェースを使ってのスタブ化を行うことができる。

これは、もともとのMockitoには無かった物議をかもすような機能である。我々はthenReturn(), thenThrow()を使ったシンプルなスタブ化を推奨する。これらはクリーンでシンプルなコードをテストするのに十分である。

 when(mock.someMethod(anyString())).thenAnswer(new Answer() {
     Object answer(InvocationOnMock invocation) {
         Object[] args = invocation.getArguments();
         Object mock = invocation.getMock();
         return "called with arguments: " + args;
     }
 });
 
 //以下は"called with arguments: foo"を表示する。
 System.out.println(mock.someMethod("foo"));

12. voidメソッドのスタブ化のためのdoThrow()|doAnswer()|doNothing()|doReturn()ファミリー(多くの場合)

voidメソッドをスタブ化するにはwhen(Object)とは異なるアプローチが必要である。なぜなら、コンパイラがカッコの中にあるvoidメソッドを嫌がるからだ。

doThrow(Throwable)はvoidメソッドをスタブ化するためのstubVoid(Object)の代わりである。 主な理由は読みやすさに加え、doAnswer()メソッドファミリーとの一貫性のためである。

voidメソッドに例外を投げさせたいときにdoThrow()を使う。

   doThrow(new RuntimeException()).when(mockedList).clear();
   
   //以下はRuntimeExceptionを投げる
   mockedList.clear();

以下のメソッドについての参照を示す。

13. リアルオブジェクトをスパイする

リアルオブジェクトに対するスパイを作成することができる。 (そのメソッドがスタブ化されていない限り)スパイのメソッドを呼び出すとリアルオブジェクトのメソッドが呼び出される。

リアルスパイは注意して時々使うようにしたい。例えば、レガシーコードを扱うような場合である。

リアルオブジェクトのスパイは「部分モッキング」に関係している。リリース1.8以前では、Mockitoスパイは部分モックではなかった。部分モックはcode smell(※)であると我々は考えるからである。

※訳注:まずいコードという意味らしい。ファウラーの「リファクタリング」が初出との説あり。

ある時点で、我々は部分モックの適当なユースケースを発見した(サードパーティ製インターフェース、レガシーコードの一時的なリファクタリングである。全文はここ)。

   List list = new LinkedList();
   List spy = spy(list);
 
   //お好みでメソッドをスタブ化する。
   when(spy.size()).thenReturn(100);
 
   //スパイを使うとリアルメソッド呼び出しになる。
   spy.add("one");
   spy.add("two");
 
   //"one"を表示する - リスト中の最初n要素である。
   System.out.println(spy.get(0));
 
   //size()メソッドはスタブ化されている - 100が表示される。
   System.out.println(spy.size());
 
   //お好みで検証する。
   verify(spy).add("one");
   verify(spy).add("two");

リアルオブジェクトをスパイする際の注意事項

1. スパイをスタブ化するためのwhen(Object)が使えない場合がある。例えば、

   List list = new LinkedList();
   List spy = spy(list);
   
   //これはできない。リアルメソッドが呼び出されてしまうため、spy.get(0)はIndexOutOfBoundsExceptionを投げる(リストはまだ空である)
   when(spy.get(0)).thenReturn("foo");
   
   //スタブ化するにはdoReturn()を使う必要がある。
   doReturn("foo").when(spy).get(0);

2. finalメソッドに注意。 Mokcitoはfinalメソッドをモックできない。so the bottom line is: when you spy on real objects + you try to stub a final method = trouble. 何が起こるかというと、リアルメソッドが(spy()メソッドの引数として与えたオブジェクトに対してではなく)モックに対して呼び出されてしまう。 多くの場合NullPointerExceptionが発生する。なぜなら、mock instances don't have fields initiated.

=== 14. スタブ化されていない呼び出しのデフォルト返り値を変更する (Since 1.7) ==

返り値について特殊な戦略を行うモックを作成することができる。 これは特に上級者向けであり、通常のテストでは必要ない。 しかし、レガシーシステムを扱う際には便利であろう。

メソッド呼び出しをスタブしない場合にのみ利用すべき、デフォルトの返り値である。

   Foo mock = mock(Foo.class, Mockito.RETURNS_SMART_NULLS);
   Foo mockTwo = mock(Foo.class, new YourOwnAnswer()); 

詳細はRETURNS_SMART_NULLSを参照のこと。

15. 後のアサーションのために引数をキャプチャする (Since 1.8.0)

Mockitoは自然なJavaスタイルで引数の検証を行う、つまりequals()メソッドを用いる。 これは引数マッチを行う場合の推奨される方法でもある。テストがクリーンでシンプルになるからだ。

しかし、ある引数について、実際の検証の後でアサーションを行った方が便利な場合がある。例えば、

   ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
   verify(mock).doSomething(argument.capture());
   assertEquals("John", argument.getValue().getName());

注意:ArgumentCaptorは検証(verification)と共に利用することが推奨されるが、しかしスタブ化とともに使わない方がよい。 スタブ化とともに使うとリーダビリティを損なう、なぜなら、Captorはassert(verify or 'then')ブロックの外で作成されるからだ. Also it may reduce defect localization because if stubbed method was not called then no argument is captured.

In a way ArgumentCaptor is related to custom argument matchers (see javadoc for ArgumentMatcher class). Both techniques can be used for making sure certain arguments where passed to mocks. However, ArgumentCaptor may be a better fit if:

  • custom argument matcher is not likely to be reused
  • you just need it to assert on argument values to complete verification

Custom argument matchers via ArgumentMatcher are usually better for stubbing.

16. Real partial mocks (Since 1.8.0)

Finally, after many internal debates & discussions on the mailing list, partial mock support was added to Mockito. Previously we considered partial mocks as code smells. However, we found a legitimate use case for partial mocks - more reading: here

Before release 1.8 spy() was not producing real partial mocks and it was confusing for some users. Read more about spying: here or in javadoc for spy(Object) method.

    //you can create partial mock with spy() method:    
    List list = spy(new LinkedList());
    
    //you can enable partial mock capabilities selectively on mocks:
    Foo mock = mock(Foo.class);
    //Be sure the real implementation is 'safe'.
    //If real implementation throws exceptions or depends on specific state of the object then you're in trouble.
    when(mock.someMethod()).thenCallRealMethod();

As usual you are going to read the partial mock warning: Object oriented programming is more less tackling complexity by dividing the complexity into separate, specific, SRPy objects. How does partial mock fit into this paradigm? Well, it just doesn't... Partial mock usually means that the complexity has been moved to a different method on the same object. In most cases, this is not the way you want to design your application.

However, there are rare cases when partial mocks come handy: dealing with code you cannot change easily (3rd party interfaces, interim refactoring of legacy code etc.) However, I wouldn't use partial mocks for new, test-driven & well-designed code.

17. Resetting mocks (Since 1.8.0)

Smart Mockito users hardly use this feature because they know it could be a sign of poor tests. Normally, you don't need to reset your mocks, just create new mocks for each test method.

Instead of reset() please consider writing simple, small and focused test methods over lengthy, over-specified tests. First potential code smell is reset() in the middle of the test method. This probably means you're testing too much. Follow the whisper of your test methods: "Please keep us small & focused on single behavior". There are several threads about it on mockito mailing list.

The only reason we added reset() method is to make it possible to work with container-injected mocks. See issue 55 (here) or FAQ (here).

Don't harm yourself. reset() in the middle of the test method is a code smell (you're probably testing too much).

   List mock = mock(List.class);
   when(mock.size()).thenReturn(10);
   mock.add(1);
   
   reset(mock);
   //at this point the mock forgot any interactions & stubbing

18. Troubleshooting & validating framework usage (Since 1.8.0)

First of all, in case of any trouble, I encourage you to read the Mockito FAQ: http://code.google.com/p/mockito/wiki/FAQ

In case of questions you may also post to mockito mailing list: http://groups.google.com/group/mockito

Next, you should know that Mockito validates if you use it correctly all the time. However, there's a gotcha so please read the javadoc for validateMockitoUsage()

19. Aliases for behavior driven development (Since 1.8.0)

Behavior Driven Development style of writing tests uses //given //when //then comments as fundamental parts of your test methods. This is exactly how we write our tests and we warmly encourage you to do so!

Start learning about BDD here: http://en.wikipedia.org/wiki/Behavior_Driven_Development

The problem is that current stubbing api with canonical role of when word does not integrate nicely with //given //when //then comments. It's because stubbing belongs to given component of the test and not to the when component of the test. Hence BDDMockito class introduces an alias so that you stub method calls with BDDMockito.given(Object) method. Now it really nicely integrates with the given component of a BDD style test!

Here is how the test might look like:

 import static org.mockito.BDDMockito.*;
 
 Seller seller = mock(Seller.class);
 Shop shop = new Shop(seller);
 
 public void shouldBuyBread() throws Exception {
   //given  
   given(seller.askForBread()).willReturn(new Bread());
   
   //when
   Goods goods = shop.buyBread();
   
   //then
   assertThat(goods, containBread());
 }  

20. (**New**) Serializable mocks (Since 1.8.1)

Mocks can be made serializable. With this feature you can use a mock in a place that requires dependencies to be serializable.

WARNING: This should be rarely used in unit testing.

The behaviour was implemented for a specific use case of a BDD spec that had an unreliable external dependency. This was in a web environment and the objects from the external dependency were being serialized to pass between layers.

To create serializable mock use MockSettings.serializable():

   List serializableMock = mock(List.class, withSettings().serializable());

The mock can be serialized assuming all the normal serialization requirements are met by the class.

Making a real object spy serializable is a bit more effort as the spy(...) method does not have an overloaded version which accepts MockSettings. No worries, you will hardly ever use it.

 List list = new ArrayList();
 List spy = mock(ArrayList.class, withSettings()
                 .spiedInstance(list)
                 .defaultAnswer(CALLS_REAL_METHODS)
                 .serializable());