Mockito @Mock、@ Spy、@ Captor、および@InjectMocksを使ってみる

Mockito @ Mock、@ Spy、@ Captor、@ InjectMocksを使ってみる

1. 概要

このチュートリアルでは、annotations of the Mockito library@Mock@Spy@Captor、および@InjectMocksについて説明します。

Mockitoの良さをさらに高めるには、have a look at the series here

参考文献:

Mockito –スパイの使用

Mockitoでスパイをうまく活用し、スパイがモックとどのように異なるか。

Mockito vs EasyMock vs JMockit

Javaモックライブラリを理解および比較するための迅速かつ実用的なガイド。

MockitoモックをSpring Beanに注入する

この記事では、依存関係注入を使用して、Mockitoモックを単体テスト用のSpring Beanに挿入する方法を示します。

2. Mockitoアノテーションを有効にする

まず、Mockitoテストでアノテーションの使用を有効にする方法を見てみましょう。

これらの注釈を有効にするには、次の例のようにannotate the JUnit test with a runnerMockitoJUnitRunnerにする必要があります。

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

または、次の例のようにMockitoAnnotations.initMocks()を呼び出すことにより、enable these annotations programmaticallyを呼び出すこともできます。

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

3. @Mock注釈

Mockitoで最も広く使用されている注釈は@Mockです。 Mockito.mockを手動で呼び出さなくても、@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 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 spyList = Mockito.spy(new ArrayList());

    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 spiedList = new ArrayList();

@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に要素を追加しました。

  • StubbedメソッドspiedList.size()は、Mockito.doReturn()を使用して2ではなく100を返します。

5. @Captor注釈

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

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

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

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

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

同じ目的でmake use of @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を使用してモックwordMapMyDictionarydicに注入します。

@Mock
Map 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 wordMap;

    public MyDictionary() {
        wordMap = new HashMap();
    }
    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 wordMap;

@Spy
MyDictionary spyDic = new MyDictionary();

However, Mockito doesn’t support injecting mocks into spies,および次のテスト結果は例外です。

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

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

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

MyDictionary(Map wordMap) {
    this.wordMap = wordMap;
}

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

@Mock
Map wordMap;

MyDictionary spyDic;

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

これでテストに合格します。

8. 注釈の使用中にNPEに遭遇する__

多くの場合、例のように、@Mockまたは@Spyで注釈が付けられたインスタンスを実際に使用しようとすると、run into NullPointerException になることがあります。

public class NPETest {

    @Mock
    List mockedList;

    @Test
    public void test() {
        Mockito.when(mockedList.size()).thenReturn(1);
    }
}

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

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

9. ノート

最後に– Mockitoアノテーションに関するsome notesは次のとおりです。

  • アノテーションを使用して、反復的なモック作成コードを最小限に抑えます

  • アノテーションを使用して、テストを読みやすくします

  • @InjectMocksを使用して、@Spyインスタンスと@Mockインスタンスの両方を挿入します

10. 結論

このクイックチュートリアルでは、annotations in the Mockito libraryの基本を示しました。

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

そしてもちろん、より多くのMockitoの良さのために、have a look at the series here