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单元测试的资料请关注脚本之家其它相关文章!

相关文章

  • 优化spring boot应用后6s内启动内存减半

    优化spring boot应用后6s内启动内存减半

    这篇文章主要为大家介绍了优化spring boot后应用6s内启动内存减半的优化示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-02-02
  • Java中替换HTML标签的方法代码

    Java中替换HTML标签的方法代码

    这篇文章主要介绍了Java中替换HTML标签的方法代码,需要的朋友可以参考下
    2014-02-02
  • 详解SpringBoot应用服务启动与安全终止

    详解SpringBoot应用服务启动与安全终止

    这篇文章主要介绍了SpringBoot应用服务启动与安全终止,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • 基于Spring Cache实现Caffeine+Redis二级缓存

    基于Spring Cache实现Caffeine+Redis二级缓存

    本文主要介绍了基于Spring Cache实现Caffeine+Redis二级缓存,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • Java wait和notify虚假唤醒原理

    Java wait和notify虚假唤醒原理

    这篇文章主要介绍了Java wait和notify虚假唤醒,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • Java日期相关API的基本操作总结

    Java日期相关API的基本操作总结

    大概总结一下日期相关API操作原因是对于日期的操作我们开发中还是很常见的,包括在数据库中保存日期,以及之前String类中对字符串的一些处理开发中都很常见,希望对大家有所帮助
    2022-11-11
  • Java常用字节流和字符流实例汇总

    Java常用字节流和字符流实例汇总

    这篇文章主要介绍了Java常用字节流和字符流实例汇总,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • 深入浅析SpringBoot自动配置原理

    深入浅析SpringBoot自动配置原理

    本文给大家介绍SpringBoot自动配置原理解析,springboot使用的是2.3.1版本源码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2021-10-10
  • springboot整合mybatis实现数据库的更新批处理方式

    springboot整合mybatis实现数据库的更新批处理方式

    这篇文章主要介绍了springboot整合mybatis实现数据库的更新批处理方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • Mybatis-plus批量去重插入ON DUPLICATE key update使用方式

    Mybatis-plus批量去重插入ON DUPLICATE key update使用方式

    这篇文章主要介绍了Mybatis-plus批量去重插入ON DUPLICATE key update使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12

最新评论