如何在 JUnit5 中使用 Mockito

How to use Mockito with JUnit5

如何在 Mockito 和 JUnit 5 中使用注入?

在 JUnit4 中,我只能使用 @RunWith(MockitoJUnitRunner.class) 注释。 JUnit5中是不是没有@RunWith注解?

您必须使用新的 @ExtendWith 注释。

遗憾的是,尚未发布任何扩展。 在 github you can see a beta implementation for the extension. as a example demo test.

有多种使用 Mockito 的方法 - 我将一一介绍。

手动

无论 JUnit 版本(或与此相关的测试框架)如何,使用 Mockito::mock 手动创建模拟都有效。

基于注释

使用 @Mock-annotation and the corresponding call to MockitoAnnotations::initMocks to create mocks 无论 JUnit 版本如何(或与此相关的测试框架,但 Java 9 可能会干扰此处,具体取决于测试代码是否在模块中结束)。

Mockito 扩展

JUnit 5 有 a powerful extension model and Mockito recently published one under the group / artifact ID org.mockito : mockito-junit-jupiter.

您可以通过将 @ExtendWith(MockitoExtension.class) 添加到测试 class 并使用 @Mock 注释模拟字段来应用扩展。来自 MockitoExtension 的 Java 文档:

@ExtendWith(MockitoExtension.class)
public class ExampleTest {

    @Mock
    private List list;

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

}

The MockitoExtension documentation 描述了实例化模拟的其他方法,例如使用构造函数注入(如果您在测试 classes 中指定最终字段)。

没有规则,没有跑步者

JUnit 4 规则和运行程序在 JUnit 5 中不起作用,因此无法使用 MockitoRule and the Mockito runner

有不同的方法,但更简洁的方法也是尊重 JUnit 5 哲学的方法是为 Mockito 创建 org.junit.jupiter.api.extension.Extension

1) Creating mocks manually 失去了额外的 Mockito 检查以确保您正确使用框架的好处。

2) 在每个测试中调用 MockitoAnnotations.initMocks(this) classes 是我们可以避免的样板代码。
并且抽象地进行此设置 class 也不是一个好的解决方案。
它将每个测试 classes 耦合到一个基础 class.
如果你出于充分的理由需要一个新的基础测试 class,你将以 3 级 class 层次结构结束。请避免这种情况。

3) 测试规则是 JUnit 4 的特性。
别想了。
documentation 对此很清楚:

However, if you intend to develop a new extension for JUnit 5 please use the new extension model of JUnit Jupiter instead of the rule-based model of JUnit 4.

4) Test Runner 确实不是扩展 JUnit 5 框架的方式。
由于 JUnit 5 扩展,JUnit 5 通过提供用于编写​​测试的扩展模型简化了 JUnit 4 的运行程序。
别想了。

所以赞成 org.junit.jupiter.api.extension.Extension 方式。


编辑:实际上,Mockito 捆绑了一个 jupiter 扩展:mockito-junit-jupiter

那么,使用起来就很简单了:

import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class FooTest {
     ...    
}

这是对 Jonathan 出色回答的补充。

通过将 mockito-junit-jupiter 工件添加为依赖项,使用 @ExtendWith(MockitoExtension.class) 会在执行测试时产生以下异常:

java.lang.NoSuchMethodError: org.junit.platform.commons.support.AnnotationSupport.findAnnotation(Ljava/util/Optional;Ljava/lang/Class;)Ljava/util/Optional;

问题是 mockito-junit-jupiter 依赖于两个独立的库。 例如 mockito-junit-jupiter:2.19.0 :

<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-core</artifactId>
  <version>2.19.0</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter-api</artifactId>
  <version>5.1.0</version>
  <scope>runtime</scope>
</dependency>

问题是我使用了 junit-jupiter-api:5.0.1

因此,junit-jupiter-api 在 API 方面仍然经常移动,请确保您所依赖的 junit-jupiter-api 版本与 mockito-junit-jupiter 所依赖的版本相同。

使用 Mockito 的 MockitoExtension。扩展包含在新工件中 mockito-junit-jupiter:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>4.5.1</version>
    <scope>test</scope>
</dependency>

它允许您像使用 JUnit 4 一样编写测试:

import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;

@ExtendWith(MockitoExtension.class)
class MyTest {

    @Mock
    private Foo foo;

    @InjectMocks
    private Bar bar; // constructor injection

    ...
}