How to drop in-memory h2db between Spring Integration tests?

北城以北 提交于 2019-12-05 10:24:16

This is because each test shares the same database and that the lifecycle of H2 is not in our control. If you start a process (the VM) and require a database named foo, close the application context, start a new one and require foo again you'll get the same instance.

In the upcoming 1.4.2 release we've added a property to generate a unique name for the database on startup (see spring.datasource.generate-unique-name) and that value will be set to true by default on 1.5.

In the meantime, you can annotate each test with @SpringBootTest(properties="spring.datasource.name=xyz") where xyz is different for a test that requires a separate DB.

Simon Ludwig

If I understand everything correctly liquibase takes care of database status. For every file, also for the test data, liquibase creates a checksum in a table to check whether something has changed or not. The h2 instance still alive after a @DirtiesContext so the checksums still exists in the database. Liquibase thinks that everything is correct but the test data may have changed.

To force liquibase to drop the database and recreate a completely new database you must set the properties in application.yml (that one for tests):

liquibase:
    contexts: test
    drop-first: true

or as an alternative you can hardcode it:

liquibase.setDropFirst(true);

You can either annotate your test with @DirtiesContext, which slows down the test because the whole application context gets rebuild.

Or you can create a custom TestExecutionListener which is much faster. I've created a custom TestExecutionListener, which recreates the database and keeps the context.

public class CleanUpDatabaseTestExecutionListener
    extends AbstractTestExecutionListener {

    @Inject
    SpringLiquibase liquibase;

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

    @Override
    public void afterTestClass(TestContext testContext) throws Exception {
        //This is a bit dirty but it works well
        testContext.getApplicationContext()
            .getAutowireCapableBeanFactory()
            .autowireBean(this);
        liquibase.afterPropertiesSet();
    }

if you are using the TestExecutionListener you must add this Listener to your test with:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest
@TestExecutionListeners(listeners = {
    DependencyInjectionTestExecutionListener.class,
    TransactionalTestExecutionListener.class,
    CleanUpDatabaseTestExecutionListener.class,
})
public class Test {
    //your tests
}

NOTE: DO NOT USE @DirtiesContext and the TestExecutionListener together, this will lead to an error.

Solved by removing username, url and password parameters.

spring:
 autoconfigure:
  exclude: org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration
 jackson:
  serialization:
   indent_output: true
 datasource:
  driver-class-name: org.hsqldb.jdbcDriver
  generate-unique-name: true
 jpa:
  hibernate:
    dialect: org.hibernate.dialect.HSQLDialect
    ddl-auto: validate
  show-sql: true
 h2:
  console:
   enabled: false

liquibase:
 change-log: classpath:/liquibase/db.changelog-master.xml
 drop-first: true
 contexts: QA
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!