Mockito 和 JUnit 入门

在本 Mockito 教程中,学习 Mockito 框架的基础知识,以及如何编写带有示例的 JUnit 测试以及 Mockito。

Mockito

在这篇 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,我们可以使用MockitoJUnitRunnerMockitoRule类。

@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() 方法,我们需要将 RecordDaoSequenceGenerator 作为依赖项注入到其中。为此,我们使用 @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 的测试示例。

祝您学习愉快!!

Github 上的源代码

评论

订阅
通知
0 条评论
最多投票
最新 最旧
内联反馈
查看所有评论

关于我们

HowToDoInJava 提供 Java 和相关技术的教程和操作指南。

它还分享最佳实践、算法和解决方案以及经常被问到的面试题。

我们的博客

REST API 教程

关注我们