Getting Started with Mockito @Mock, @Spy, @Captor and @InjectMocks – 开始使用Mockito @Mock、@Spy、@Captor和@InjectMocks

最后修改: 2014年 11月 15日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll cover the following annotations of the Mockito library: @Mock, @Spy, @Captor, and @InjectMocks.

在本教程中,我们将介绍Mockito库的以下注释:@Mock@Spy@Captor@InjectMocks

For more Mockito goodness, have a look at the series here.

关于更多Mockito的好处,看一下这里的系列

2. Enable Mockito Annotations

2.启用Mockito注解

Before we go further, let’s explore different ways to enable the use of annotations with Mockito tests.

在我们进一步讨论之前,让我们来探讨一下在Mockito测试中启用注释的不同方法。

2.1. MockitoJUnitRunner

2.1.MockitoJUnitRunner

The first option we have is to annotate the JUnit test with a MockitoJUnitRunner:

我们的第一个选择是MockitoJUnitRunner注释JUnit测试。

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

2.2. MockitoAnnotations.openMocks()

2.2.MockitoAnnotations.openMocks()

Alternatively, we can enable Mockito annotations programmatically by invoking MockitoAnnotations.openMocks():

另外,我们可以通过调用MockitoAnnotations.openMocks(),以编程方式启用Mockito注释。

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

2.3. MockitoJUnit.rule()

2.3.MockitoJUnit.rule()

Lastly, we can use a MockitoJUnit.rule():

最后,我们可以使用一个MockitoJUnit.rule()

public class MockitoInitWithMockitoJUnitRuleUnitTest {

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

    ...
}

In this case, we must remember to make our rule public.

在这种情况下,我们必须记住使我们的规则公开

3. @Mock Annotation

3.@Mock 注释

The most widely used annotation in Mockito is @Mock. We can use @Mock to create and inject mocked instances without having to call Mockito.mock manually.

Mockito中最广泛使用的注解是@Mock。我们可以使用@Mock来创建和注入模拟实例,而不必手动调用Mockito.mock

In the following example, we’ll create a mocked ArrayList manually without using the @Mock annotation:

在下面的例子中,我们将手动创建一个模拟的ArrayList而不使用@Mock注解。

@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());
}

Now we’ll do the same, but we’ll inject the mock using the @Mock annotation:

现在我们将做同样的事情,但我们将使用@Mock注解注入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());
}

Note how in both examples, we’re interacting with the mock and verifying some of these interactions, just to make sure that the mock is behaving correctly.

请注意,在这两个例子中,我们都与mock进行了交互,并验证了其中的一些交互,只是为了确保mock的行为是正确的。

4. @Spy Annotation

4.@Spy 注释

Now let’s see how to use the @Spy annotation to spy on an existing instance.

现在让我们看看如何使用@Spy注解来监视一个现有的实例。

In the following example, we create a spy of a List without using the @Spy annotation:

在下面的例子中,我们创建了一个List的间谍,但没有使用@Spy注解。

@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());
}

Now we’ll do the same thing, spy on the list, but we’ll use the @Spy annotation:

现在我们将做同样的事情,监视列表,但我们将使用@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());
}

Note how, as before, we’re interacting with the spy here to make sure that it behaves correctly. In this example we:

请注意,和以前一样,我们在这里与间谍进行互动,以确保它的行为正确。在这个例子中,我们。

  • Used the real method spiedList.add() to add elements to the spiedList.
  • Stubbed the method spiedList.size() to return 100 instead of 2 using Mockito.doReturn().

5. @Captor Annotation

5.@Captor 注释

Next let’s see how to use the @Captor annotation to create an ArgumentCaptor instance.

接下来让我们看看如何使用@Captor注解来创建一个ArgumentCaptor实例。

In the following example, we’ll create an ArgumentCaptor without using the @Captor annotation:

在下面的例子中,我们将创建一个ArgumentCaptor而不使用@Captor注解。

@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());
}

Now let’s make use of @Captor for the same purpose, to create an ArgumentCaptor instance:

现在让我们利用@Captor来达到同样的目的,创建一个ArgumentCaptor实例。

@Mock
List mockedList;

@Captor 
ArgumentCaptor argCaptor;

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

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

Notice how the test becomes simpler and more readable when we take out the configuration logic.

请注意,当我们把配置逻辑拿出来时,测试变得更简单,更易读。

6. @InjectMocks Annotation

6.@InjectMocks 注释

Now let’s discuss how to use the @InjectMocks annotation to inject mock fields into the tested object automatically.

现在让我们讨论如何使用@InjectMocks注解来自动注入模拟字段到被测对象中。

In the following example, we’ll use @InjectMocks to inject the mock wordMap into the MyDictionary dic:

在下面的例子中,我们将使用@InjectMocks来把模拟的wordMap注入到MyDictionary 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"));
}

Here is the class MyDictionary:

这里是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. Injecting a Mock Into a Spy

7.向间谍注入模拟信号

Similar to the above test, we might want to inject a mock into a spy:

与上面的测试类似,我们可能想在一个间谍中注入一个模拟。

@Mock
Map<String, String> wordMap;

@Spy
MyDictionary spyDic = new MyDictionary();

However, Mockito doesn’t support injecting mocks into spies, and the following test results in an exception:

然而,Mockito并不支持将mock注入spies中,而且下面的测试结果是一个异常。

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

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

If we want to use a mock with a spy, we can manually inject the mock through a constructor:

如果我们想在间谍中使用一个模拟,我们可以通过构造函数手动注入这个模拟。

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

Instead of using the annotation, we can now create the spy manually:

现在我们可以不使用注解,而是手动创建间谍。

@Mock
Map<String, String> wordMap; 

MyDictionary spyDic;

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

The test will now pass.

现在测试将通过。

8. Running Into NPE While Using Annotation

8.使用注释时遇到NPE

Often we may run into NullPointerException when we try to actually use the instance annotated with @Mock or @Spy:

通常,当我们试图实际使用用@Mock@Spy注释的实例时,我们可能会遇到NullPointerException

public class MockitoAnnotationsUninitializedUnitTest {

    @Mock
    List<String> mockedList;

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

Most of the time, this happens simply because we forget to properly enable Mockito annotations.

大多数时候,发生这种情况只是因为我们忘记了正确地启用Mockito注释。

So we have to keep in mind that each time we want to use Mockito annotations, we must take the extra step and initialize them as we already explained earlier.

因此,我们必须记住,每次我们想使用Mockito注释时,我们必须采取额外的步骤并初始化它们,正如我们已经解释过的早些时候

9. Notes

9.注释

Finally, here are some notes about Mockito annotations:

最后,这里有关于Mockito注释的一些说明

  • Mockito’s annotations minimize repetitive mock creation code.
  • They make tests more readable.
  • @InjectMocks is necessary for injecting both @Spy and @Mock instances.

10. Conclusion

10.结论

In this brief article, we explained the basics of annotations in the Mockito library.

在这篇简短的文章中,我们解释了Mockito库中的注释的基本知识

The implementation of all of these examples can be found over on GitHub. This is a Maven project, so it should be easy to import and run as it is.

所有这些例子的实现都可以在GitHub上找到over。这是一个Maven项目,所以应该很容易导入并按原样运行。

Of course, for more Mockito goodness, have a look at the series here.

当然,对于更多Mockito的好处,看一下这里的系列