在 JUnit 5 测试中模拟 Spring Boot 2 应用程序的自动装配依赖项

Posted

技术标签:

【中文标题】在 JUnit 5 测试中模拟 Spring Boot 2 应用程序的自动装配依赖项【英文标题】:Mock autowired dependency in JUnit 5 test for Spring Boot 2 app 【发布时间】:2018-03-28 02:28:27 【问题描述】:

考虑下面的测试类:

public class SomeClass 

    @Autowired
    private SomeDependency someDependency;

    public int inc(int i) 
        someDependency.doSomething();
        return i + 1;
    


如何在 Spring Boot 2 (2.0.0.M2) 应用程序的 JUnit 5 (5.0.1) 测试中模拟(最好使用 Mockito)someDependency?当我尝试调用SomeClass#inc(int) 时,它会产生NullPointerException,因为未注入自动装配的依赖项。

【问题讨论】:

你应该显示测试类。 @davidxxx 我认为它不包含有用的信息。我只需要一种注入模拟的方法。 【参考方案1】:

Mockito 1 运行器(MockitoJUnitRunner 类)不是为运行 JUnit 5 测试而设计的。

所以用 :

注释你的类
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class) 
public class MyJUnit5Test 

不会有任何影响。

为了能够使用@Mock 注解,您可以在每次测试之前调用:

 MockitoAnnotations.initMocks(this);

在使用 JUnit 5 @BeforeEach 注释的方法中。 但是从现在开始,在每个 JUnit 测试类中不重复此预处理的更好选择是使用MockitoExtension class provided by the mockito-junit-jupiter dependency。


代码示例

假设SomeDependency 类声明为:

@Component
public class SomeDependency 

    public String returnThat() 
        return "that";
    

您可以在单元测试中以这种方式模拟依赖项:

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;

import davidhxxx.example.angularsboot.SomeDependency;

@ExtendWith(MockitoExtension.class)    
public class SomeClassTest 

    @Mock
    SomeDependency someDependencyMock;

    private SomeClass someClass;

    @BeforeEach
    public void setup()
      someClass = new SomeClass(someDependencyMock);
    

    @Test 
    void myFirstTest() 
      Mockito.when(someDependencyMock.returnThat()).thenReturn("mock result");
      Assertions.assertEquals("mock result", someClass.inc());
    


请注意,SomeClass 必须提供一种方法来设置其 SomeDependency 依赖项。 您应该添加一个接受的实例的构造函数。 使用setter 也是一种提供可变性的方法。


pom.xml 要求

1) 您可以在继承的依赖项中添加包含 Mockito 和其他有用内容的 the spring-boot-starter-test 依赖项:

<dependencies>
    ...
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
   ...
</dependencies>

还添加 junit-jupiter-engine 依赖项和您需要的所有其他可选 JUnit 5 依赖项:

<dependencies>
    ...
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-junit-jupiter</artifactId>
        <version>2.18.0</version> <!-- version to specify as not provided by Spring Boot dependencies -->
        <scope>test</scope>
    </dependency>
</dependencies>

您不需要为 junit-jupiter-engine 工件指定版本,但您可能需要其他 JUnit 5 依赖项,例如 junit-jupiter-params。 希望在下一个版本的 Spring Boot 中不再需要这个。

2) 注意:如果您使用的 Spring Boot 版本会拉 2.20 版的maven-surefire-plugin 就不行了。因此,您必须覆盖 maven-surefire-plugin 插件配置以指定与 JUnit 5 兼容的版本(即 2.19 或 2.21 及更高版本)。 例如 Spring Boot 的 2.0.0.M5 版本拉取 maven-surefire-plugin:2.20 ,因此需要重新配置插件,如下所示:

    <plugins>
        ...
        <plugin>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.19</version>
            <dependencies>
                <dependency>
                    <groupId>org.junit.platform</groupId>
                    <artifactId>junit-platform-surefire-provider</artifactId>
                    <version>1.0.0</version>
                </dependency>
            </dependencies>
        </plugin>
     ...
   <plugins>

它会产生一个 Maven 警告:

覆盖 maven-surefire-plugin 的托管版本 2.20.1

好消息:从 Spring Boot 的 2.0.1.RELEASE 版本开始,这个问题得到了解决,因为 maven-surefire-plugin 版本已更新为使用 2.21.0 以及解决该问题的更高版本。

【讨论】:

感谢您提供的出色示例。我不知何故仍然得到NullPointerException(见编辑)。顺便说一句:我正在尝试测试SomeClass,而不是SomeDependency 这可行,但前提是我添加了相应的构造函数(目前,没有SomeClass(@Autowired SomeDependency sd))。 当然。有一个构造函数来定义依赖是一件好事。 “隐藏”依赖项作为私有字段不会使类可测试。 确实,谢谢! (感谢您指出 Surefire 插件的问题,我之前一直在努力解决这个问题。) 为了完整起见:从2.21.0 版本开始,Failsafe 插件支持 JUnit 5,无需额外配置。 (附带 Spring Boot 2.0.1.RELEASE。)

以上是关于在 JUnit 5 测试中模拟 Spring Boot 2 应用程序的自动装配依赖项的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JUnit 在 Spring Boot 中的公共方法中模拟私有方法

spring boot 测试类

在Junit 5测试中注入Spring数据存储库

如何在用 Kotlin 编写的 JUnit 5 测试类中注入 Spring bean?

将 JUnit JPA 测试从 Spring 2.5.5 迁移到 Spring 3.0.4

Junit / Spring Boot 模拟类