Spring Boot 集成 JUnit 单元测试

简介: 本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。

为自己的应用编写单元测试是一个很好的习惯。在Java开发中最流行的测试工具非JUnit莫属,它已经成为Java单元测试的事实标准。Spring Boot测试模块不仅集成JUnit框架,还提供了许多实用程序和注释,方便我们测试应用。

1. 添加依赖

在 pom.xml 文件中引入 spring-boot-starter-test

xml

体验AI代码助手

代码解读

复制代码

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<version>${version}</version>
	<scope>test</scope>
</dependency>

Spring Boot 2.2.x 开始集成的是JUnit 5。如果之前是使用的JUnit 4,可以使用JUnit 5中提供的老式引擎运行,需要添加 junit-vintage-engine 依赖。

Spring Boot 2.2.x发布很久了,现在最新稳定版是2.4.x。旧的总要被替代,所以本篇只用JUnit 5,关于JUnit 4的文章相信网上很多,官方也有给出使用说明,请自行查找。

2. 编写单元测试

java

体验AI代码助手

代码解读

复制代码

@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class JUnitTest {

    @Test
    public void test() {
        // 测试代码
    }
}

@SpringBootTest 重要参数

  • args应用程序参数,如:args = "--app.test=one"
  • classesSpring Boot应用启动入口类名,该参数不指定时由Spring Boot默认查找。
  • webEnvironment默认情况下@SpringBootTest不会启动服务器。当测试Web应用时,需指定该参数以便加载上下文环境。

WebEnvironment枚举值说明:

  • MOCK默认值,加载WebApplicationContext并提供模拟Web环境。使用此注释时,不会启动嵌入式服务器。
  • RANDOM_PORT启动应用并随机监听一个端口。
  • DEFINED_PORT启动应用并监听自定义的端口(来自application.properties)或使用默认端口8080。
  • NONEApplicationContext通过使用加载,SpringApplication但不提供任何网络环境(模拟或其他方式)。

@Test

注意 JUnit 5 的 @Test 注解在 org.junit.jupiter.api 包下。


如果应用使用Spring MVC和 Spring WebFlux,则优先MVC。测试WebFlux应用必须设置:

xml

体验AI代码助手

代码解读

复制代码

@SpringBootTest(properties = "spring.main.web-application-type=reactive")
public class MyWebFluxTests {

}

3. 自动装配测试

有时候我们只需要测试框架模块集成是否正常,不需要加载整个项目。可以使用 spring-boot-test-autoconfigure 模块中一些注解。整个框架被“切片”成独立的测试模块。

JSON 测试

测试JSON序列化与反序列化。如果是GSON或JSONB,使用 @GsonTester 或 @JsonbTester 注解。

java

体验AI代码助手

代码解读

复制代码

/**
 * @author Engr-Z
 * @since 2021/1/18
 */
@JsonTest
public class MyJsonTest {

    @Autowired
    private JacksonTester<Map> json;

    @Test
    void testSerialize() throws Exception {
        Map<String, Object> map = new HashMap<>();
        map.put("name", "攻城狮·正");
        map.put("websit", "engr-z.com");
        
        Assertions.assertThat(this.json.write(map)).isEqualToJson("expected.json");
        Assertions.assertThat(this.json.write(map)).hasJsonPathStringValue("@.make");
        Assertions.assertThat(this.json.write(map)).extractingJsonPathStringValue("@.make")
                .isEqualTo("Honda");
    }

    @Test
    void testDeserialize() throws Exception {
        String content = "{\"name\":\"攻城狮·正\",\"website\":\"engr-z.com\"}";
        Assertions.assertThat(this.json.parse(content));
        Assertions.assertThat(this.json.parseObject(content).get("website")).isEqualTo("engr-z.com");
    }

}

Spring MVC 测试

测试 /demo/hello 接口是否正常

java

体验AI代码助手

代码解读

复制代码

/**
 * @author Engr-Z
 * @since 2021/1/18
 */
@WebMvcTest(DemoController.class)
public class SpringMVCTest {

    @Autowired
    private MockMvc mvc;

    @Test
    void test() throws Exception {
        RequestBuilder builder = MockMvcRequestBuilders.get("/demo/hello");
        ResultActions resultActions = mvc.perform(builder);
        int status = resultActions.andReturn().getResponse().getStatus();
        Assertions.assertEquals(200, status);
    }
}

Spring WebFlux 测试

java

体验AI代码助手

代码解读

复制代码

/**
 * @author Engr-Z
 * @since 2021/1/18
 */
@WebFluxTest(DemoController.class)
public class SpringWebFluxTest {

    @Autowired
    private WebTestClient webClient;

    @Test
    void test() throws Exception {
        webClient.get().uri("/demo/webflux")
                .accept(MediaType.TEXT_PLAIN)
                .exchange()
                .expectStatus().isOk();
    }
}

JDBC 测试

java

体验AI代码助手

代码解读

复制代码

@JdbcTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class JdbcTransactionalTests {

}

自动装配还支持 JPA,Redis,Rest Client 等模块测试。更多请参考:Auto-configured Tests

@MockBean 和 @SpyBean

如果一个服务依赖于远程调用的结果。为了不影响我们做单元测试,可以使用@MockBean。以下是官方代码示例:

java

体验AI代码助手

代码解读

复制代码

@SpringBootTest
class MyTests {

    @MockBean
    private RemoteService remoteService;

    @Autowired
    private Reverser reverser;

    @Test
    void exampleTest() {
        // RemoteService has been injected into the reverser bean
        BDDMockito.given(this.remoteService.someCall()).willReturn("mock");
        String reverse = reverser.reverseSomeCall();
        Assertions.assertThat(reverse).isEqualTo("kcom");
    }

}

@SpyBean@MockBean 不同之处是:对于未指定mock的方法,spy默认会调用真实的方法,有返回值的返回真实的返回值,而mock默认不执行,有返回值的,默认返回null


转载来源:https://juejin.cn/post/6919073817667059726

相关文章
|
25天前
|
Java 数据库连接 数据库
Spring boot 使用mybatis generator 自动生成代码插件
本文介绍了在Spring Boot项目中使用MyBatis Generator插件自动生成代码的详细步骤。首先创建一个新的Spring Boot项目,接着引入MyBatis Generator插件并配置`pom.xml`文件。然后删除默认的`application.properties`文件,创建`application.yml`进行相关配置,如设置Mapper路径和实体类包名。重点在于配置`generatorConfig.xml`文件,包括数据库驱动、连接信息、生成模型、映射文件及DAO的包名和位置。最后通过IDE配置运行插件生成代码,并在主类添加`@MapperScan`注解完成整合
Spring boot 使用mybatis generator 自动生成代码插件
|
3月前
|
Python
Python教程:os 与 sys 模块详细用法
os 模块用于与操作系统交互,主要涉及夹操作、路径操作和其他操作。例如,`os.rename()` 重命名文件,`os.mkdir()` 创建文件夹,`os.path.abspath()` 获取文件绝对路径等。sys 模块则用于与 Python 解释器交互,常用功能如 `sys.path` 查看模块搜索路径,`sys.platform` 检测操作系统等。这些模块提供了丰富的工具,便于开发中处理系统和文件相关任务。
122 14
|
7月前
|
前端开发 JavaScript Java
java常用数据判空、比较和类型转换
本文介绍了Java开发中常见的数据处理技巧,包括数据判空、数据比较和类型转换。详细讲解了字符串、Integer、对象、List、Map、Set及数组的判空方法,推荐使用工具类如StringUtils、Objects等。同时,讨论了基本数据类型与引用数据类型的比较方法,以及自动类型转换和强制类型转换的规则。最后,提供了数值类型与字符串互相转换的具体示例。
286 3
|
3月前
|
消息中间件 Java Kafka
Spring Boot整合kafka
本文简要记录了Spring Boot与Kafka的整合过程。首先通过Docker搭建Kafka环境,包括Zookeeper和Kafka服务的配置文件。接着引入Spring Kafka依赖,并在`application.properties`中配置生产者和消费者参数。随后创建Kafka配置类,定义Topic及重试机制。最后实现生产者发送消息和消费者监听消息的功能,支持手动ACK确认。此方案适用于快速构建基于Spring Boot的Kafka消息系统。
196 7
|
4月前
|
人工智能 Java
Java 中数组Array和列表List的转换
本文介绍了数组与列表之间的相互转换方法,主要包括三部分:1)使用`Collections.addAll()`方法将数组转为列表,适用于引用类型,效率较高;2)通过`new ArrayList&lt;&gt;()`构造器结合`Arrays.asList()`实现类似功能;3)利用JDK8的`Stream`流式计算,支持基本数据类型数组的转换。此外,还详细讲解了列表转数组的方法,如借助`Stream`实现不同类型数组间的转换,并附带代码示例与执行结果,帮助读者深入理解两种数据结构的互转技巧。
106 1
Java 中数组Array和列表List的转换
|
6月前
|
测试技术 数据库 Python
Python装饰器实战:打造高效性能计时工具
在数据分析中,处理大规模数据时,分析代码性能至关重要。本文介绍如何使用Python装饰器实现性能计时工具,在不改变现有代码的基础上,方便快速地测试函数执行时间。该方法具有侵入性小、复用性强、灵活度高等优点,有助于快速发现性能瓶颈并优化代码。通过设置循环次数参数,可以更准确地评估函数的平均执行时间,提升开发效率。
183 61
Python装饰器实战:打造高效性能计时工具
|
3月前
|
负载均衡 前端开发 Java
SpringCloud调用组件Feign
本文深入探讨微服务Spring体系中的Feign组件。Feign是一个声明式Web服务客户端,支持注解、编码器/解码器,与Spring MVC注解兼容,并集成Eureka、负载均衡等功能。文章详细介绍了SpringCloud整合Feign的步骤,包括依赖引入、客户端启用、接口创建及调用示例。同时,还涵盖了Feign的核心配置,如超时设置、拦截器实现(Basic认证与自定义)和日志级别调整。最后,总结了`@FeignClient`常用属性,帮助开发者更好地理解和使用Feign进行微服务间通信。
204 1
|
3月前
|
缓存 监控 Java
java动态代理
本文介绍了Java中的动态代理及其优势,通过增强原有方法或拦截调用实现无侵入式代码扩展,如添加日志、缓存等。文章先讲解了静态代理的基本概念和实现方式,随后引出动态代理解决静态代理在多方法、多类场景下的局限性。通过JDK提供的InvocationHandler接口和Proxy类,展示了如何动态生成代理对象。最后,文章还探讨了代理Hook技术,包括寻找Hook点、选择代理方式以及替换原始对象的具体步骤。
104 0
|
4月前
|
Java C++
JVM之符号引用和直接引用
本文介绍了Java中直接引用和符号引用的概念及其区别。直接引用与虚拟机布局相关,包括指向目标的指针、相对偏移量或间接句柄,通常在目标已被加载到内存时使用。符号引用则涉及编译原理,包含类/接口全限定名、字段及方法的名称和描述符,在Class文件中保存,需在运行时解析为具体内存地址。文中还详细说明了描述符规则以及数组类型的表示方式,帮助理解Java虚拟机的动态链接过程。
|
4月前
|
SQL 负载均衡 关系型数据库
MySQL复制以及调优
本文介绍了MySQL自带复制方案的实现及其注意事项。复制方案能提供数据备份、负载均衡与分布式数据管理的优势。文章详细描述了复制步骤:主库(master)记录更改到二进制日志,发送同步消息给从库(slave),从库接收后将日志复制到本地并执行。实现复制包括配置主库的server-id和二进制日志、创建复制账号、初始化主库数据、设置从库参数及开启复制。此外,还探讨了三种日志格式(row、statement、mixed)的特点及选择建议,并分析了主从复制延迟的优化方法,如控制事务大小、优化日志传输和多线程还原日志等。最后,文中列出了搭建过程中需要注意的关键点。