# Mockito 注解– `@Mock`，`@Spy`，`@Captor`，`@InjectMock`

> 原文： [https://howtodoinjava.com/mockito/mockito-annotations/](https://howtodoinjava.com/mockito/mockito-annotations/)

在此 Mockito 教程中，了解 **Mockito 注解**，例如`@Mock`，`@Spy`，`@Captor`，`@InjectMock`。 学习使用模仿注解为行为测试编写单元测试。

## 1\. Mockito 注解

#### 1.1 `@Mock`

`@Mock`注解用于创建和注入模拟实例。 我们不创建真实的对象，而是要求模拟为类创建一个模拟。

`@Mock`注解是`Mockito.mock(classToMock)`的替代方法。 它们都达到相同的结果。 通常认为使用`@Mock`是“**清洁器**”，因为我们没有用看起来都一样的样板分配填充测试。

使用`@Mock`注解：

*   允许快速创建测试所需的对象。
*   最小化重复的模拟创建代码。
*   使测试类更具可读性。
*   由于使用字段名称来识别模拟，因此使验证错误更易于阅读。

在给定的示例中，我们模拟了`HashMap`类。 在实际测试中，我们将模拟实际的应用类。 我们在映射中放置了一个键值对，然后验证了对模拟映射实例执行了方法调用。

```java
@Mock
HashMap<String, Integer> mockHashMap;

@Test
public void saveTest()
{
	mockHashMap.put("A", 1);

	Mockito.verify(mockHashMap, times(1)).put("A", 1);
	Mockito.verify(mockHashMap, times(0)).get("A");

	assertEquals(0, mockHashMap.size());
}

```

#### 1.2 `@Spy`

`@Spy`注解用于**创建真实对象并监视该真实对象**。 间谍程序可以帮助调用对象的所有常规方法，同时仍可以跟踪每次交互，就像使用模拟一样。

请注意，在给定的示例中，由于我们向其中添加了一个键值对，因此映射的大小如何保持为 1。 我们还可以使用它的键取回添加到映射的值。 在模拟实例中是不可能的。

```java
@Spy
HashMap<String, Integer> hashMap;

@Test
public void saveTest()
{
	hashMap.put("A", 10);

	Mockito.verify(hashMap, times(1)).put("A", 10);
	Mockito.verify(hashMap, times(0)).get("A");

	assertEquals(1, hashMap.size());
	assertEquals(new Integer(10), (Integer) hashMap.get("A"));
}

```

###### `@Mock`和`@Spy`之间的区别

使用`@Mock`时，mockito 将创建类的准系统的 shell 实例，完全可以跟踪与之的交互。 这不是真实的对象，也不维护其状态更改。

使用`@Spy`时，mockito 创建类的真实实例并跟踪与之的每次交互。 它保持状态更改。

#### 1.3 `@Captor`

`@Captor`注解用于创建`ArgumentCaptor`实例，该实例用于**捕获方法参数值**进行进一步的声明。

请注意，mockito 使用参数类的`equals()`方法验证参数值。

```java
@Mock
HashMap<String, Integer> hashMap;

@Captor
ArgumentCaptor<String> keyCaptor;

@Captor
ArgumentCaptor<Integer> valueCaptor;

@Test
public void saveTest() 
{
	hashMap.put("A", 10);

	Mockito.verify(hashMap).put(keyCaptor.capture(), valueCaptor.capture());

	assertEquals("A", keyCaptor.getValue());
	assertEquals(new Integer(10), valueCaptor.getValue());
}

```

#### 1.4 `@InjectMock`

在模拟中，我们需要创建要测试的类的对象，然后插入其依赖项（*模拟*）以完全测试行为。 为此，我们使用`@InjectMock`注解。

`@InjectMock`标记应在其上执行注射的字段。 Mockito 将尝试仅通过构造器注入，设置器注入或属性注入按此顺序注入模拟。 如果任何给定的注射策略失败，则 Mockito 不会报告失败。

> 阅读更多： [`@Mock`和`@InitMock`注解之间的区别](https://howtodoinjava.com/mockito/mockito-mock-initMock/)

## 2\. 如何初始化 Mockito 注解

为了使用上述注解，测试类应使用以下三种给定方法之一初始化注解：

1.  在单元测试课的顶部使用`@RunWith(MockitoJUnitRunner.class)`。

    ```java
    @RunWith(MockitoJUnitRunner.class)
    public class ExampleTest {

        @Mock
        private List list;

        @Test
        public void shouldDoSomething() {
            list.add(100);
        }
    }

    ```

2.  在单元测试类的`@Before`方法中使用`MockitoAnnotations.initMock(this)`。

    ```java
    public class ExampleTest {

        @Mock
        private List list;

        @Before
        public void setup() {
            MockitoAnnotations.initMock(this);
        }

        @Test
        public void shouldDoSomething() {
            list.add(100);
        }
    }

    ```

3.  使用`MockitoJUnit.rule()`创建`MockitoRule`类。

    ```java
    public class ExampleTest {

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

        @Mock
        private List list;

        @Test
        public void shouldDoSomething() {
            list.add(100);
        }
    }

    ```

在评论中，将您与 Mockito 注解有关的问题放到我这里。

学习愉快！

参考文献：

[`Mock` Java Doc](https://static.javadoc.io/org.mockito/mockito-core/2.23.4/org/mockito/Mock.html)
[`Spy` Java Doc](https://static.javadoc.io/org.mockito/mockito-core/2.23.4/org/mockito/Spy.html)
[`Captor` Java Doc](https://static.javadoc.io/org.mockito/mockito-core/2.23.4/org/mockito/Captor.html)
[`InjectMock` Java Doc](https://static.javadoc.io/org.mockito/mockito-core/2.23.4/org/mockito/InjectMock.html)