如何在每个测试方法之前和之后执行sql脚本

Posted

技术标签:

【中文标题】如何在每个测试方法之前和之后执行sql脚本【英文标题】:How to execute sql script before and after each test method 【发布时间】:2020-10-25 21:55:49 【问题描述】:

spring中有一个@Sql注解,允许在测试方法前后执行sql代码:

@Test
@Sql("init.sql")
@Sql(scripts = "clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
public void someTest()


但是,我有几种测试方法,我想提供与上述测试相同的干净环境,并且我不想为每个测试重复相同的 @Sql 注释。如何为所有方法做一次?例如:

// JPA and Spring other test annotations
@Sql("init.sql")
@Sql(scripts = "clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
public class TestClass

  // init.sql executed before every test, clean.sql executed after every test

【问题讨论】:

【参考方案1】:

确实,当您将@Sql 放在class 上时,sql 脚本将在该类中定义的每个测试之前和之后执行,更具体地说,在@Before 之前和@After 方法之后.所以,

// JPA and Spring other test annotations
@Sql("init.sql")
@Sql(scripts = "clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
public class TestClass

  // init.sql executed before every test, clean.sql executed after every test

将根据@Sql 定义工作:

@Target(ElementType.TYPE, ElementType.METHOD)
/// other annotations
public @interface Sql 
   //

【讨论】:

【参考方案2】:

如果我的理解是正确的,你是想执行一个init脚本把DB置于某个状态,然后在每个测试方法之前确保DB回到那个状态,对吧?

那么最简单的解决方案是使用@Transactional。默认情况下,Spring Boot 会自动回滚 @Transactional-annotated 测试的测试事务,从而将 DB 重置为原始状态。

不过,有两个缺点应该考虑:

    @Transactional 表示将存在一个跨越测试方法的整个执行的事务,测试的服务方法通常会加入该事务。因此,不能依靠测试本身来验证生产代码中事务边界的正确性(例如,LazyInitializationExceptions 可能被这个“外部”事务覆盖) 除非必要,否则不会刷新持久性上下文,这意味着某些问题(例如违反数据库约束)不会出现。我倾向于使用最后机会冲洗来解决这个问题,如下所示:
  @After
  public void flushContext() 
    if (TransactionSynchronizationManager.isActualTransactionActive()) 
      entityManager.flush();
    
  

【讨论】:

回答第一个问题:是的,这正是我想要实现的。我使用@DataJpaTest,所以无论如何都会使用@Transactional。我想运行 init 和 clear 脚本的原因是因为无法回滚的序列,所以在 init.sql 和 clean.sql 中我删除序列并重新创建它们从而具有完全干净的状态。感谢您对@Transactional 的第一条评论非常好。

以上是关于如何在每个测试方法之前和之后执行sql脚本的主要内容,如果未能解决你的问题,请参考以下文章

junit5常用注解

SpringBoot中的测试(test)

如何使用休眠执行 sql-script 文件?

VS2010 负载测试:如何执行在每次负载测试之前运行一次的自定义操作

在 Maven/Junit/DBUnit 项目的集成测试之前/之后创建/删除数据库的最佳方法?

在 py.test 中的每个测试之前和之后运行代码?