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

Java 如何在每个测试方法之前和之后执行sql脚本,java,spring,spring-boot,jpa,junit,Java,Spring,Spring Boot,Jpa,Junit,spring中有一个@Sql注释,允许在测试方法之前和之后执行Sql代码: @Test @Sql("init.sql") @Sql(scripts = "clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) public void someTest() { } 但是,我有几种测试方法,我希望提供与上述测试相同的干净环境,并且我不希望对每个测试重复相同的@Sql注释。如何做到一

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
}

实际上,当您将
@Sql
放在
类上时,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 {
   //
}

如果我的理解是正确的,那么您希望执行一个init脚本,将DB置于某个状态,然后确保DB在每个测试方法之前回到该状态,对吗

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

虽然有两个缺点,但应该考虑:

  • @Transactional
    表示在测试方法的整个执行过程中将存在一个事务,测试的服务方法通常会加入该事务。因此,不能依靠测试本身来验证生产代码中事务边界的正确性(
    LazyInitializationException
    s可能包含在此“外部”事务中)
  • 除非必要,否则持久性上下文不会刷新,这意味着某些问题(例如,DB约束冲突)将不会出现。我倾向于利用最后的机会来解决这个问题,比如:

  • 回答第一个问题:是的,这正是我想要实现的。我使用的是
    @DataJpaTest
    ,因此仍然使用
    @Transactional
    。我之所以要运行init和clear脚本,是因为序列无法回滚,所以在init.sql和clean.sql中,我会删除序列,然后重新创建它们,使其处于完全干净的状态。感谢您对
    @Transactional
    的第一句评论,非常好。
      @After
      public void flushContext() {
        if (TransactionSynchronizationManager.isActualTransactionActive()) {
          entityManager.flush();
        }
      }