在这篇 Mockito 教程 中,学习 Mockito 框架的基础知识,以及如何使用示例编写 JUnit 测试和 Mockito。
@ExtendWith(MockitoExtension.class)
public class ItemServiceTest {
@Mock
private ItemRepository itemRepository;
@InjectMocks
private ItemService itemService; // Assuming ItemService uses ItemRepository
@Test
public void testCreateItem() {
// ...
}
}
1. Mockito 简介
Mockito 是一个开源框架,可以让我们轻松创建 测试双胞胎(mock)。‘测试双胞胎’是任何将生产对象替换为测试目的的情况的通用术语。
在 Mockito 中,我们通常使用以下类型的测试双胞胎。
- Stub(桩) – 是具有预定义返回值的对象,这些返回值在测试期间方法执行时使用。
- Spy(间谍) – 与桩类似,但它们还会记录执行方式的统计信息。
- Mock – 是在测试过程中具有方法执行返回值并记录了这些执行期望的对象。如果 Mock 收到它不期望的调用,它会抛出异常,并且在验证期间会检查它是否收到了所有预期的调用。
在测试类中,我们可以 Mock 接口和类。Mockito 还可以通过使用 Mockito 注解来生成最少的样板代码。
创建后,Mock 会记住所有交互。然后我们可以选择性地验证我们感兴趣的任何交互。
2. Mockito 与 JUnit 的设置
2.1. Maven
要将 Mockito 添加到项目,我们可以通过任何方式(例如 Maven、Gradle 或 Jar 文件)添加最新的 Mockito 版本。
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
testCompile group: 'org.mockito', name: 'mockito-core', version: '4.6.1'
2.2. 使用 JUnit 5 引导
要使用 JUnit 5 使用 Mockito,请添加Junit Jupiter依赖项。
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
要使用 JUnit 5 处理 Mockito 注解,我们需要使用MockitoExtention,如下所示
@ExtendWith(MockitoExtension.class)
public class ApplicationTest {
//code
}
2.2. 使用 JUnit 4 引导 [遗留]
要使用 JUnit 4 使用 Mockito,请添加Junit 4依赖项。
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
对于遗留的JUnit 4,我们可以使用MockitoJUnitRunner或MockitoRule类。
@RunWith(MockitoJUnitRunner.class)
public class ApplicationTest {
//code
}
@RunWith(MockitoJUnitRunner.class)
public class ApplicationTest {
@Rule
public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
//code
}
严格的桩法确保干净的测试,减少测试代码的重复,并提高调试能力。当被测代码使用不同的参数调用桩方法时,或者存在未使用的桩时,测试会尽早失败。
2.3. 编程初始化
或者,我们可以在基类或测试运行器中的某个位置使用 openMocks() 方法以编程方式引导 Mockito。该方法初始化使用 Mockito 注解 @Mock、@Spy、@Captor、@InjectMocks 注解的字段。
之前使用的 initMocks() 方法现已弃用。
@BeforeEach
public void setup() {
MockitoAnnotations.openMocks(this);
}
3. Mockito 注解
在开始编写单元测试之前,让我们快速浏览一下有用的 Mockito 注解。
- @Mock 用于创建 mock 对象。它使测试类更易读。
- @Spy 用于创建 spy 实例。我们可以用它代替
spy(Object)方法。 - @InjectMocks 用于自动实例化被测对象,并将所有用 @Mock 或 @Spy 注解的字段依赖项注入到其中(如果适用)。值得了解 @Mock 和 @InitMocks 注解之间的区别。
- @Captor 用于创建参数捕获器。
public class ApplicationTest {
@Mock
Depedency mock;
@InjectMocks
Service codeUnderTest;
}
4. Mockito 演示
4.1. 被测系统
为了演示 Mockito 语法,我们创建了一个典型的用例,其中 RecordService 调用 RecordDao 来保存一个 Record。
RecordService 使用 SequenceGenerator 类来获取下一个记录 ID。
4.2. 测试演示
- 为了测试 RecordService.saveRecord() 方法,我们需要将 RecordDao 和 SequenceGenerator 作为依赖项注入到其中。为此,我们使用 @Mock 和 @InjectMocks 注解。
- @ExtendWith(MockitoExtension.class) 开始引导过程,并将 mock 对象注入到服务实例中。
- 我们使用 when(…).then(…) 方法来记录 mock 对象的期望,并在应用程序代码执行完成后,使用 verify() 方法调用来验证这些期望。
- 最后,如果需要,我们可以使用额外的 JUnit 断言 进行额外的验证。
@ExtendWith(MockitoExtension.class)
public class MockitoHelloTest {
@Mock
RecordDao mockDao;
@Mock
NotificationService mockNotification;
@Mock
SequenceGenerator mockGenerator;
@InjectMocks
RecordService service;
@Test
public void testSaveRecord() {
Record record = new Record();
record.setName("Test Record");
when(mockGenerator.getNext()).thenReturn(100L);
when(mockDao.saveRecord(record)).thenReturn(record);
Record savedRecord = service.saveRecord(record);
verify(mockGenerator, times(1)).getNext();
verify(mockDao, times(1)).saveRecord(any(Record.class));
assertEquals("Test Record", savedRecord.getName());
assertEquals(100L, savedRecord.getId());
}
}
5. 结论
在本 Mockito JUnit 教程 中,我们学习了使用 mockito 框架进行 mocking 和 stubbing 的基础知识。我们学习了如何在 JUnit 4 和 5 环境中引导 mocking 过程。
最后,我们看到了一个使用 mockito 和 junit 的测试示例。
祝您学习愉快!!
评论