SpringBoot单元测试之数据隔离详解

 更新时间:2023年08月23日 11:36:17   作者:哒哒哒打代码  
我们在写单元测试时,有一个比较重要的要求是可以重复运行, 那么这样就会有一个比较麻烦的问题:数据污染,所以本文为大家整理了两个数据隔离的方式,希望对大家有所帮助

前言

我们在写单元测试时,有一个比较重要的要求是可以重复运行,即只要外部参数不变,那么一定可以获取确定的结果。 那么这样就会有一个比较麻烦的问题:数据污染。 以数据库操作为例,对于一些查询类的测试用例倒还好,因为只要保证数据存在,那么查询操作天生就是幂等的,不管你查多少次,数据都不会变。 但是对于写入操作就不友好了,每一次运行单元测试,都会在数据库中产生新的数据,可能在第一次运行时正常,第二次运行时就由于数据冲突导致失败。那对于这种情况,我们应该如何去解决?

下面分享两种我使用过的数据隔离的方式,供大家参考。

数据隔离

测试事务

这种方式比较常规,适用场景也比较广泛,即我们在测试用例中,通过@Transactional注解开始事务,此时整个单元测试方法会被包裹在事务中,并且会在运行结束后,自动回滚。

我们可以在类或方法上添加@Transactional注解

/**
 * 在类上添加 @Transactional 注解,可以让测试方法在执行完毕后自动回滚,不会对数据库造成影响。
 * 如果在方法上添加,则只影响对应的方法
 */
@SpringBootTest
@Transactional
public class TransactionalTests extends AbstractTransactionalJUnit4SpringContextTests {
    @Resource
    private UserService userService;
    @Test
    void createRecord() {
        User user = userService.createUser();
        //to other things
    }
}

或者继承AbstractTransactionalJUnit4SpringContextTests

/**
 * 在类上添加 @Transactional 注解,可以让测试方法在执行完毕后自动回滚,不会对数据库造成影响。
 * 如果在方法上添加,则只影响对应的方法
 */
@SpringBootTest
public class TransactionalTests extends AbstractTransactionalJUnit4SpringContextTests {
    @Resource
    private UserService userService;
    @Test
    void createRecord() {
        User user = userService.createUser();
        //to other things
    }
}

AbstractTransactionalJUnit4SpringContextTests实际上也是添加了@Transactional注解,只不过在此之外,它还提供了一些JDBC接口,可以让我们更方便的操作数据库。

使用这种方式来实现单元测试的话,由于测试用例中的所有数据库操作都在事务中进行,然后运行结束后事务回滚,就可以保证不会染污数据库数据,做到数据隔离。但是它也存在一些问题:

  • 影响单元测试结果,在方法上层添加事务,本质上还是改变了方法的逻辑。比如说我被测试的方法中用到了不同的数据源(主从数据库),一但被包裹了事务,那么意味着我在这个事务内,都是使用同一条连接,这会对我们实际上期望运行的逻辑生产影响。
  • 排查问题困难,因为在单元测试运行结束之后,事务最终会回滚,也就意味着我们DB最终是没有数据的,很难排查问题。

数据预处理与清理

上面说到事务会存在一些问题,那么我们不使用事务,怎么保证数据隔离?我们可以通过几种方式来在单元测试运行前后手动的增加或清理数据:

通过@Sql注解来定义单元测试前后需要执行的SQL脚本

    @Sql(
            scripts = "create-data.sql",
            config = @SqlConfig(transactionMode = ISOLATED)
    )
    @Sql(
            scripts = "delete-data.sql",
            config = @SqlConfig(transactionMode = ISOLATED),
            executionPhase = AFTER_TEST_METHOD
    )
    @Test
    void createRecord() {
        User user = userService.createUser();
        //to other things
    }

我们通过@Sql注解定义指定了两个SQL脚本,分别用于在运行单元测试前创建测试数据,以及在运行结束后,删除数据,这样就可以保证我们的每次运行单元测试时的数据都是隔离的。

@Sql只是一种方式,我们还可以通过其它各种方式来执行,比如@BeforeEach、@AfterEach来定义单元测试执行前后的拦截器,或者Junit的@ExtendWith来定义外部的监听器等各种方式来处理数据的预处理与清理。

总结

上面分享了两种数据隔离的方式,一般情况下都可以满足我们的单元测试需求,但是实际上两种方式都还存在一些问题,比如不管是哪种方式,都依赖于外部的数据库,如果我们依赖的数据库出现了异常,也会影响到我们的单元测试运行。而且使用外部数据库也是无法完全做到数据隔离的,还是会有数据冲突的风险。那还有没有更好的方法? 如果大家的单元测试环境有docker环境的话,那么可以考虑引入Testcontainers,可以很好的解决这个问题。下篇文章我会详细讲一下Testcontainers在单测数据隔离中的实践。

以上就是SpringBoot单元测试之数据隔离详解的详细内容,更多关于SpringBoot单元测试的资料请关注脚本之家其它相关文章!

相关文章

  • java切分字符串的2种方法实例

    java切分字符串的2种方法实例

    在我们日常工作中经常遇到截取字符串的需求,下面这篇文章主要给大家介绍了关于java切分字符串的2种方法,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • Spring boot admin 服务监控利器详解

    Spring boot admin 服务监控利器详解

    这篇文章主要介绍了Spring boot admin 服务监控利器详解,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-08-08
  • Java通过反射机制将对象封装成JSON和JsonArray格式

    Java通过反射机制将对象封装成JSON和JsonArray格式

    这篇文章主要介绍了Java通过反射机制将对象封装成JSON和JsonArray格式,JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法,需要的朋友可以参考下
    2023-10-10
  • 使用SpringBoot+Prometheus+Grafana实现可视化监控

    使用SpringBoot+Prometheus+Grafana实现可视化监控

    本文主要给大家介绍了如何使用Spring actuator+监控组件prometheus+数据可视化组件grafana来实现对Spring Boot应用的可视化监控,文中有详细的代码供大家参考,具有一定的参考价值,需要的朋友可以参考下
    2024-02-02
  • 详解springboot如何更新json串里面的内容

    详解springboot如何更新json串里面的内容

    这篇文章主要为大家介绍了springboot 如何更新json串里面的内容,文中有详细的解决方案供大家参考,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2023-10-10
  • Java8(291)之后禁用了TLS1.1使JDBC无法用SSL连接SqlServer2008的解决方法

    Java8(291)之后禁用了TLS1.1使JDBC无法用SSL连接SqlServer2008的解决方法

    这篇文章主要介绍了Java8(291)之后禁用了TLS1.1使JDBC无法用SSL连接SqlServer2008的解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • Java中常见的陷阱题及答案

    Java中常见的陷阱题及答案

    在电脑里找到一份当时学习JAVA时的笔记,看到一些现在已经遗忘的细节。稍微整理了几个,发出来与大家分享。这篇文章主要介绍了Java中常见的陷阱题及答案,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-01-01
  • 解决引入spring-cloud-starter-openfeign后部分类找不到的问题

    解决引入spring-cloud-starter-openfeign后部分类找不到的问题

    这篇文章主要介绍了解决引入spring-cloud-starter-openfeign后部分类找不到的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Java数据结构之ArrayList从顺序表到实现

    Java数据结构之ArrayList从顺序表到实现

    Java中的ArrayList是一种基于数组实现的数据结构,支持动态扩容和随机访问元素,可用于实现顺序表等数据结构。ArrayList在内存中连续存储元素,支持快速的随机访问和遍历。通过学习ArrayList的实现原理和使用方法,可以更好地掌握Java中的数据结构和算法
    2023-04-04
  • springboot2.x 接入阿里云市场短信发送的实现

    springboot2.x 接入阿里云市场短信发送的实现

    本文主要介绍了springboot2.x 接入阿里云市场短信发送的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11

最新评论