# Mockito – `@Mock`和`@InjectMock`注解之间的区别

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

在使用 [junit](https://howtodoinjava.com/junit-4/) 和 Mockito 进行[单元测试](https://howtodoinjava.com/best-practices/unit-testing-best-practices-junit-reference-guide/)的过程中，我们使用`@Mock`和`@InjectMock`注解来创建要测试的对象和依赖项。 了解 mockito 中`@Mock`和`@InjectMock`注解之间的*区别*。

## 1\. 模拟对象与存根对象之间的区别

重要的是要了解模拟对象与[存根对象](https://howtodoinjava.com/java/basics/how-to-create-a-class-in-java/)之间的区别。 对象是类的实际实例，使用对象引用调用的任何方法都将执行类文件中定义的方法主体。

模拟对象是用于隐藏无法在测试环境中测试的依赖项的接口。 数据库，网络位置等。使用模拟引用调用的方法不会执行类文件中定义的方法主体，而是使用`when-thenReturn`方法组合来配置方法行为。

在 junit 测试中，我们为需要测试的类和要调用的方法创建对象。 我们为依赖项创建了模拟，这些依赖项不会出现在测试环境中，并且对象依赖于该依赖项来完成方法调用。

## 2\. `@Mock`和`@InjectMock`之间的区别

在基于 Mockito 的 junit 测试中，**`@Mock`注解创建模拟，而`@InjectMock`创建类对象**。

> `@Mock` – 创建模拟
> `@InjectMock` – 创建对象并注入模拟的依赖项

*   使用`@InjectMock`创建需要在测试类中进行测试的类实例。
*   当需要为给定类执行实际方法主体时，请使用`@InjectMock`。
*   当我们需要使用模拟对象初始化的所有内部依赖项以正常工作方法时，请使用`@InjectMock`。
*   使用`@Mock`创建模拟，以支持要测试的类的测试。
*   带有`@Mock`注解的带注解的类（待测试）依赖项。
*   我们必须为模拟对象定义`when-thenRetrun`方法，在实际测试执行期间将调用哪些类方法。

## 3\. `@Mock`和`@InjectMock`示例

让我们通过示例来了解`@Mock`和`@InjectMock`之间的区别。 在此示例中，我们具有类`MainClass`，其类具有方法`save()`。

`MainClass`依赖于`DatabaseDAO`和`NetworkDAO`。 当我们调用`MainClass.save()`方法时，它在内部调用两个相关对象的保存方法。

#### 3.1 Java 类

```java
public class MainClass {

	DatabaseDAO database;
	NetworkDAO network;

	//Setters and getters

	public boolean save(String fileName) 
	{
		database.save(fileName);
		System.out.println("Saved in database in Main class");

		network.save(fileName);
		System.out.println("Saved in network in Main class");

		return true;
	}
}

```

```java
public class DatabaseDAO {
	public void save(String fileName) {
		System.out.println("Saved in database");
	}
}

```

```java
public class NetworkDAO {
	public void save(String fileName) {
		System.out.println("Saved in network location");
	}
}

```

#### 3.2 `MainClass`的 Junit 测试

让我们为`MainClass`编写 junit 测试。

```java
import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMock;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

public class ApplicationTest 
{
	@InjectMock
	MainClass mainClass;

	@Mock
	DatabaseDAO dependentClassOne;

	@Mock
	NetworkDAO dependentClassTwo;

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

	@Test
	public void validateTest()
	{
		boolean saved = mainClass.save("temp.txt");
		assertEquals(true, saved);
	}
}

```

测试成功执行，我们在控制台中获得以下语句。 **仔细观察控制台输出。**

```java
Saved in database in Main class
Saved in network in Main class

```

在上面的测试中，将打印用`MainClass.save()`方法编写的语句，但不打印从属类。 它证明了方法主体仅针对`MainClass`的`save()`方法执行，因为我们使用`@InjectMock`注解创建了`MainClass`的实际对象。 对于依赖类，我们使用了模拟。

#### 3.3 验证模拟的方法调用

要验证是否已调用模拟方法，我们必须使用模拟提供的工具方法`verify()`。 它有助于验证在执行实际的测试类方法时是否已执行了模拟方法。

```java
@Test
public void validateTest()
{
	boolean saved = mainClass.save("temp.txt");
	assertEquals(true, saved);

	verify(dependentClassOne, times(1)).save("temp.txt");
	verify(dependentClassTwo, times(1)).save("temp.txt");
}

```

## 4 总结

在此 mockito 教程中，我们了解了`@Mock`和`@InjectMock`注解之间的*区别*。 我们了解了在 junit 测试中将这些注解应用于类时发生了什么。

学习愉快！

参考： [Mockito 指南](https://static.javadoc.io/org.mockito/mockito-core/2.23.4/org/mockito/Mockito.html)