简体   繁体   中英

How to execute sql script before and after each test method

There is an @Sql annotation in spring which allows to execute sql code before and after the test method:

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

However I have several test methods where I would like to provide the same clean environment like in the test above and I don't want to repeat for every test the same @Sql annotation. How to do it once for all methods? For example:

// 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
}

Indeed when you place @Sql on the class , sql scripts will be executed before and after every test defined in that class, more specifically before @Before and after @After methods. So,

// 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
}

is going to work according to the @Sql definition:

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

If my understanding is correct, you want to execute an init script to put the DB in a certain state, and then ensure the DB is back to that state before each test method, right?

The simplest solution is to use @Transactional , then. By default, Spring Boot will automatically roll back the test transaction of a @Transactional -annotated test, thus resetting the DB to the original state.

There are two downsides one should consider, though:

  1. @Transactional means there will exist a transaction spanning the entire execution of the test method which the tested service methods will typically join. Hence, the test itself cannot be relied upon to verify the correctess of transactional boundaries in the production code ( LazyInitializationException s may be covered by this 'outer' transacion, for example)
  2. The persistence context will not flush unless necessary, meaning that some issues (eg DB constraint violations) will not surface. I tend to work around that issue using a last-chance flush like so:
  @After
  public void flushContext() {
    if (TransactionSynchronizationManager.isActualTransactionActive()) {
      entityManager.flush();
    }
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM