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输入学号、姓名、年龄并对其进行输出的实现方法

    Java输入学号、姓名、年龄并对其进行输出的实现方法

    这篇文章主要给大家介绍了关于Java输入学号、姓名、年龄并对其进行输出的实现方法,在计算机编程中,输出学号和姓名是一个常见的任务,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-09-09
  • 一文秒懂java到底是值传递还是引用传递

    一文秒懂java到底是值传递还是引用传递

    这篇文章主要介绍了java到底是值传递还是引用传递的相关知识,本文通过几个例子给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • 通过实例解析spring bean之间的关系

    通过实例解析spring bean之间的关系

    这篇文章主要介绍了通过实例解析spring bean之间的关系,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • java 进制转换实例详解

    java 进制转换实例详解

    这篇文章主要介绍了java 进制转换实例详解的相关资料,需要的朋友可以参考下
    2017-04-04
  • springboot themaleaf 第一次进页面不加载css的问题

    springboot themaleaf 第一次进页面不加载css的问题

    这篇文章主要介绍了springboot themaleaf 第一次进页面不加载css的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • 学习Java内存模型JMM心得

    学习Java内存模型JMM心得

    这篇文章主要介绍了学习Java内存模型JMM的心得以及对其原理做了深入的介绍,有兴趣的朋友学习下吧。
    2017-12-12
  • 一文详解Java闭锁和栅栏的实现

    一文详解Java闭锁和栅栏的实现

    闭锁与栅栏是在多线程编程中的概念,因为在多线程中,我们不能控制线程的执行状态,所以给线程加锁,让其按照我们的想法有秩序的执行。本文将详解Java闭锁和栅栏的实现,需要的可以参考一下
    2022-06-06
  • Java并发编程之阻塞队列深入详解

    Java并发编程之阻塞队列深入详解

    这篇文章主要介绍了详解Java阻塞队列(BlockingQueue)的实现原理,阻塞队列是Java util.concurrent包下重要的数据结构,是一种特殊的队列,需要的朋友可以参考下
    2021-10-10
  • idea中创建jsp项目的详细实战步骤

    idea中创建jsp项目的详细实战步骤

    才学javaWeb,以防自己忘记创建项目的过程,所以浅浅的记录一下吧,下面这篇文章主要给大家介绍了关于idea中创建jsp项目的详细步骤,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2022-09-09
  • Java数据结构之有向图的拓扑排序详解

    Java数据结构之有向图的拓扑排序详解

    这篇文章主要为大家详细介绍了Java数据结构中有向图的拓扑排序,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以了解一下
    2022-11-11

最新评论