SpringBoot - 不要在 Spring Boot 集成测试中使用 @Transactional

简介: SpringBoot - 不要在 Spring Boot 集成测试中使用 @Transactional

在测试运行时,测试类中 @Transactional 注解,会导致测试中 Entity 数据的操作都是在内存中完成,最终并不会进行 commit 操作,也就是不会将 Entity 数据进行持久化操作,从而导致测试的行为和真实应用的行为不一致。

事务管理在应用开发中是种不可或缺的设计,它是数据库持久化处理的一种标准。我们知道,应用程序开发离不开对数据的CRUD(增删改查),事务的ACID可以更好保证数据的完整性,保证相关数据的同生共死。单个事务生命周期主要分为三个阶段,BEGIN TRANSACTION -> COMMIT TRANSACTION -> ROLLBACK TRANSACTION

Spring Boot事务的使用分为命令式声明式常用的方式是声明式注解(@Transactional)。事务管理既可以在应用层使用,也可以在测试中使用。

为了保证测试之间的相互独立,测试之间数据不会被相互影响。也许你写过这样的测试:


@SpringBootTest
@ActiveProfiles("test")
@Transactional
public class UserControllerTest { }

@Transactional 通过将数据持久化操作截断,来解决测试之间相互对立,数据相互不影响的问题。然而这样方式会有副作用,就是数据持久化的过程不再真实,没有了commit的过程。从而会导致:

  • 无法保证 Entity 之间关联关系,唯一索引和主外键关联的准确性
  • 无法保证 Entity 创建时间、更新时间和版本化(乐观锁)的赋值逻辑的准确性
  • 无法保证 Entity 中有 @Transient 注解的属性的赋值逻辑的准确性
  • 测试的数据不是真实场景存在的问题
  • 测试中,单个事务中的准备数据,无法在多线程中共享。

......

然后 Spring 在测试问题域中引入事务管理初衷是什么?为了解决什么问题才需要将它引入?官方文档介绍 Transaction management


image.png


按照官方文档意思,为了解决测试运行时,程序访问真实的数据库,改变数据的状态,从而影响到后续的测试问题。

其实这里应该批判性思维一下,为什么测试运行时,需要访问真实的数据库?为什么测试之间的数据会相互影响?

对于每个测试来说,每次运行前都应该有干净的上下文,或者说独立的上下文,有数据清理和准备的过程,测试与测试之间相互隔离。也就是说,为什么测试不能用内存数据库或者嵌入式数据库?为什么不是每个测试运行前清理一下数据库中的数据,保证测试用例运行前的一方净土,不被上个测试数据影响?

答案当然是,可以!!!

写在最后

如何做?实现一个 TruncateDatabaseService,只删除表的数据,不删除表的结果。 在测试基类的@BeforeEach,执行 truncate。源码Truncate Database

目录
相关文章
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
1388 0
|
10月前
|
Java 测试技术 数据库连接
【SpringBoot(四)】还不懂文件上传?JUnit使用?本文带你了解SpringBoot的文件上传、异常处理、组件注入等知识!并且带你领悟JUnit单元测试的使用!
Spring专栏第四章,本文带你上手 SpringBoot 的文件上传、异常处理、组件注入等功能 并且为你演示Junit5的基础上手体验
1189 3
|
Java 测试技术 开发者
必学!Spring Boot 单元测试、Mock 与 TestContainer 的高效使用技巧
【10月更文挑战第18天】 在现代软件开发中,单元测试是保证代码质量的重要手段。Spring Boot提供了强大的测试支持,使得编写和运行测试变得更加简单和高效。本文将深入探讨Spring Boot的单元测试、Mock技术以及TestContainer的高效使用技巧,帮助开发者提升测试效率和代码质量。
1559 2
|
人工智能 Java 测试技术
SpringBoot 测试实践:单元测试与集成测试
在 Spring Boot 测试中,@MockBean 用于创建完全模拟的 Bean,替代真实对象行为;而 @SpyBean 则用于部分模拟,保留未指定方法的真实实现。两者结合 Mockito 可灵活控制依赖行为,提升测试覆盖率。合理使用 @ContextConfiguration 和避免滥用 @SpringBootTest 可优化测试上下文加载速度,提高测试效率。
630 5
|
XML Java 测试技术
【SpringBoot系列】初识Springboot并搭建测试环境
【SpringBoot系列】初识Springboot并搭建测试环境
377 0
|
Java 测试技术 Spring
简单学Spring Boot | 博客项目的测试
本内容介绍了基于Spring Boot的博客项目测试实践,重点在于通过测试驱动开发(TDD)优化服务层代码,提升代码质量和功能可靠性。案例详细展示了如何为PostService类编写测试用例、运行测试并根据反馈优化功能代码,包括两次优化过程。通过TDD流程,确保每项功能经过严格验证,增强代码可维护性与系统稳定性。
450 0
|
Java 关系型数据库 MySQL
深入解析 @Transactional——Spring 事务管理的核心
本文深入解析了 Spring Boot 中 `@Transactional` 的工作机制、常见陷阱及最佳实践。作为事务管理的核心注解,`@Transactional` 确保数据库操作的原子性,避免数据不一致问题。文章通过示例讲解了其基本用法、默认回滚规则(仅未捕获的运行时异常触发回滚)、因 `try-catch` 或方法访问修饰符不当导致失效的情况,以及数据库引擎对事务的支持要求。最后总结了使用 `@Transactional` 的五大最佳实践,帮助开发者规避常见问题,提升项目稳定性与可靠性。
2157 12
|
XML Java 应用服务中间件
Spring Boot 两种部署到服务器的方式
本文介绍了Spring Boot项目的两种部署方式:jar包和war包。Jar包方式使用内置Tomcat,只需配置JDK 1.8及以上环境,通过`nohup java -jar`命令后台运行,并开放服务器端口即可访问。War包则需将项目打包后放入外部Tomcat的webapps目录,修改启动类继承`SpringBootServletInitializer`并调整pom.xml中的打包类型为war,最后启动Tomcat访问应用。两者各有优劣,jar包更简单便捷,而war包适合传统部署场景。需要注意的是,war包部署时,内置Tomcat的端口配置不会生效。
3294 17
Spring Boot 两种部署到服务器的方式
|
Java 测试技术 应用服务中间件
Spring Boot 如何测试打包部署
本文介绍了 Spring Boot 项目的开发、调试、打包及投产上线的全流程。主要内容包括: 1. **单元测试**:通过添加 `spring-boot-starter-test` 包,使用 `@RunWith(SpringRunner.class)` 和 `@SpringBootTest` 注解进行测试类开发。 2. **集成测试**:支持热部署,通过添加 `spring-boot-devtools` 实现代码修改后自动重启。 3. **投产上线**:提供两种部署方案,一是打包成 jar 包直接运行,二是打包成 war 包部署到 Tomcat 服务器。
578 10
|
JavaScript NoSQL Java
基于SpringBoot+Vue实现的大学生体质测试管理系统设计与实现(系统源码+文档+数据库+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!