1. 概要

このチュートリアルでは、Mockitoライブラリの次のアノテーションについて説明します: @Mock @Spy @Captor 、および@InjectMocks

Mockitoの優れた点については、こちらのシリーズをご覧ください。

2. Mockito注釈を有効にする

先に進む前に、Mockitoテストでアノテーションを使用できるようにするさまざまな方法を調べてみましょう。

2.1. MockitoJUnitRunner

最初のオプションは、JUnitテストにMockitoJUnitRunnerで注釈を付けることです。

@RunWith(MockitoJUnitRunner.class)
public class MockitoAnnotationTest {
    ...
}

2.2. MockitoAnnotations.initMocks()

または、 MockitoAnnotations.initMocks()を呼び出すことにより、プログラムでMockitoアノテーションを有効にすることができます。

@Before
public void init() {
    MockitoAnnotations.initMocks(this);
}

2.3. MockitoJUnit.rule()

最後に、 MockitoJUnit.rule()を使用できます。

public class MockitoInitWithMockitoJUnitRuleUnitTest {

    @Rule
    public MockitoRule initRule = MockitoJUnit.rule();

    ...
}

この場合、ルールをpublicにすることを忘れないでください。

3. @Mockアノテーション

Mockitoで最も広く使用されているアノテーションは、@Mockです。 @Mock を使用すると、 Mockito.mock を手動で呼び出さなくても、モックされたインスタンスを作成して挿入できます。

次の例では、 @Mock アノテーションを使用せずに、モックされたArrayListを手動で作成します。

@Test
public void whenNotUseMockAnnotation_thenCorrect() {
    List mockList = Mockito.mock(ArrayList.class);
    
    mockList.add("one");
    Mockito.verify(mockList).add("one");
    assertEquals(0, mockList.size());

    Mockito.when(mockList.size()).thenReturn(100);
    assertEquals(100, mockList.size());
}

ここでも同じことを行いますが、@Mockアノテーションを使用してモックを注入します。

@Mock
List<String> mockedList;

@Test
public void whenUseMockAnnotation_thenMockIsInjected() {
    mockedList.add("one");
    Mockito.verify(mockedList).add("one");
    assertEquals(0, mockedList.size());

    Mockito.when(mockedList.size()).thenReturn(100);
    assertEquals(100, mockedList.size());
}

どちらの例でも、モックが正しく動作していることを確認するために、モックと対話し、これらの対話の一部を検証していることに注意してください。

4. @Spyアノテーション

次に、@Spyアノテーションを使用して既存のインスタンスをスパイする方法を見てみましょう。

次の例では、@Spyアノテーションを使用せずにListのスパイを作成します。

@Test
public void whenNotUseSpyAnnotation_thenCorrect() {
    List<String> spyList = Mockito.spy(new ArrayList<String>());
    
    spyList.add("one");
    spyList.add("two");

    Mockito.verify(spyList).add("one");
    Mockito.verify(spyList).add("two");

    assertEquals(2, spyList.size());

    Mockito.doReturn(100).when(spyList).size();
    assertEquals(100, spyList.size());
}

今度は同じことを行い、リストをスパイしますが、@Spyアノテーションを使用します。

@Spy
List<String> spiedList = new ArrayList<String>();

@Test
public void whenUseSpyAnnotation_thenSpyIsInjectedCorrectly() {
    spiedList.add("one");
    spiedList.add("two");

    Mockito.verify(spiedList).add("one");
    Mockito.verify(spiedList).add("two");

    assertEquals(2, spiedList.size());

    Mockito.doReturn(100).when(spiedList).size();
    assertEquals(100, spiedList.size());
}

以前と同様に、ここでスパイとやり取りして、スパイが正しく動作することを確認していることに注意してください。 この例では、次のようにします。

  • realメソッドspiedList.add()を使用して、spiedListに要素を追加しました。
  • スタブメソッドspiedList.size()は、 Mockito.doReturn()を使用して2ではなく100を返します。 。

5. @Captorアノテーション

次に、@Captorアノテーションを使用してArgumentCaptorインスタンスを作成する方法を見てみましょう。

次の例では、@Captorアノテーションを使用せずにArgumentCaptorを作成します。

@Test
public void whenNotUseCaptorAnnotation_thenCorrect() {
    List mockList = Mockito.mock(List.class);
    ArgumentCaptor<String> arg = ArgumentCaptor.forClass(String.class);

    mockList.add("one");
    Mockito.verify(mockList).add(arg.capture());

    assertEquals("one", arg.getValue());
}

次に、で@Captor を同じ目的で使用して、ArgumentCaptorインスタンスを作成しましょう。

@Mock
List mockedList;

@Captor 
ArgumentCaptor argCaptor;

@Test
public void whenUseCaptorAnnotation_thenTheSam() {
    mockedList.add("one");
    Mockito.verify(mockedList).add(argCaptor.capture());

    assertEquals("one", argCaptor.getValue());
}

構成ロジックを削除すると、テストがより単純で読みやすくなることに注目してください。

6. @InjectMocksアノテーション

次に、 @InjectMocks アノテーションを使用して、テスト対象のオブジェクトにモックフィールドを自動的に挿入する方法について説明します。

次の例では、 @InjectMocks を使用して、モックwordMapMyDictionary dicに注入します。

@Mock
Map<String, String> wordMap;

@InjectMocks
MyDictionary dic = new MyDictionary();

@Test
public void whenUseInjectMocksAnnotation_thenCorrect() {
    Mockito.when(wordMap.get("aWord")).thenReturn("aMeaning");

    assertEquals("aMeaning", dic.getMeaning("aWord"));
}

クラスMyDictionaryは次のとおりです。

public class MyDictionary {
    Map<String, String> wordMap;

    public MyDictionary() {
        wordMap = new HashMap<String, String>();
    }
    public void add(final String word, final String meaning) {
        wordMap.put(word, meaning);
    }
    public String getMeaning(final String word) {
        return wordMap.get(word);
    }
}

7. スパイにモックを注入する

上記のテストと同様に、スパイにモックを注入したい場合があります。

@Mock
Map<String, String> wordMap;

@Spy
MyDictionary spyDic = new MyDictionary();

ただし、Mockitoはスパイへのモックの注入をサポートしていません。次のテスト結果は例外です。

@Test 
public void whenUseInjectMocksAnnotation_thenCorrect() { 
    Mockito.when(wordMap.get("aWord")).thenReturn("aMeaning"); 

    assertEquals("aMeaning", spyDic.getMeaning("aWord")); 
}

スパイでモックを使用したい場合は、コンストラクターを介してモックを手動で挿入できます。

MyDictionary(Map<String, String> wordMap) {
    this.wordMap = wordMap;
}

注釈を使用する代わりに、スパイを手動で作成できるようになりました。

@Mock
Map<String, String> wordMap; 

MyDictionary spyDic;

@Before
public void init() {
    MockitoAnnotations.initMocks(this);
    spyDic = Mockito.spy(new MyDictionary(wordMap));
}

テストに合格します。

8. アノテーションの使用中にNPEに実行

@Mockまたは@Spyで注釈が付けられたインスタンスを実際に使用しようとすると、NullPointerExceptionが発生することがよくあります。

public class MockitoAnnotationsUninitializedUnitTest {

    @Mock
    List<String> mockedList;

    @Test(expected = NullPointerException.class)
    public void whenMockitoAnnotationsUninitialized_thenNPEThrown() {
        Mockito.when(mockedList.size()).thenReturn(1);
    }
}

ほとんどの場合、これは、Mockitoアノテーションを適切に有効にするのを忘れたために発生します。

したがって、Mockitoアノテーションを使用するたびに、前にで説明したように、追加の手順を実行して初期化する必要があることに注意する必要があります。

9. ノート

最後に、Mockitoアノテーションに関するいくつかのメモを次に示します。

  • Mockitoの注釈は、繰り返しのモック作成コードを最小限に抑えます。
  • それらはテストをより読みやすくします。
  • @InjectMocks は、@Spy@Mockの両方のインスタンスを注入するために必要です。

10. 結論

この短い記事では、Mockitoライブラリアノテーションの基本について説明しました。

これらすべての例の実装は、GitHubにあります。 これはMavenプロジェクトなので、そのままインポートして実行するのは簡単です。

もちろん、Mockitoの良さについては、こちらのシリーズをご覧ください。