Я использую Liquibase в своем веб-приложении Spring. У меня есть группа объектов с сотнями тестов для API REST в тестах интеграции для каждого объекта, такого как User, Account, Invoice, License и т. Д. Все мои тесты интеграции проходят при запуске по классу, но многие из них терпят неудачу при совместном использовании gradle test
. Скорее всего, есть столкновение данных между тестами, и я не заинтересован в том, чтобы тратить время на исправление очистки данных на данный момент. Я предпочитаю отбрасывать БД и контекст после каждого класса. Я решил, что могу использовать @DirtiesContext
в классе, и поэтому я аннотировал его с помощью теста.Как сбросить память h2db в памяти между тестами интеграции Spring?
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Application.class, SecurityConfiguration.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@DirtiesContext
public class InvoiceResourceIntTest {
Я вижу, что после добавления аннотаций, контекст веб-приложение запускается для каждого класса, но при инициализации LiquiBase происходит, запросы не выполняются, так как контрольная сумма матчей. Поскольку это БД в памяти, я ожидал, что БД будет уничтожена вместе с весенним контекстом, но этого не происходит.
Я также установил jpa hibernate ddl-auto в create-drop
, но это не помогло. Следующая опция, которую я рассматриваю, это вместо mem
, напишите h2db в файл и удалите этот файл в @BeforeClass моих файлов тестовых файлов интеграции. Я предпочитаю автоматически отбрасывать db в памяти вместо управления им в тесте, но хочу попробовать здесь как последний вариант. Спасибо за помощь.
Update:
Я обновил тест, как показано ниже.
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Application.class, SecurityConfiguration.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = "spring.datasource.name=AccountResource")
@DirtiesContext
public class AccountResourceIntTest {
У меня есть уникальные имена для каждого теста интеграции. Я до сих пор не вижу, что база данных является новой, потому что я вижу только контрольную сумму Liquibase в журналах.
Вот мое приложение конфигурации из application.yml
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:myApp;DB_CLOSE_DELAY=-1
name:
username:
password:
jpa:
database-platform: com.neustar.registry.le.domain.util.FixedH2Dialect
database: H2
open-in-view: false
show_sql: true
hibernate:
ddl-auto: create-drop
naming-strategy: org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy
properties:
hibernate.cache.use_second_level_cache: false
hibernate.cache.use_query_cache: false
hibernate.generate_statistics: true
hibernate.hbm2ddl.auto: validate
Мой проект генерируется из JHipster версии 2.x, если это имеет значение. См. Ниже мой класс конфигурации базы данных. AppProperties - это специфичные для приложения свойства (в отличие от Spring).
@Configuration
public class DatabaseConfiguration {
private static final int LIQUIBASE_POOL_INIT_SIZE = 1;
private static final int LIQUIBASE_POOL_MAX_ACTIVE = 1;
private static final int LIQUIBASE_POOL_MAX_IDLE = 0;
private static final int LIQUIBASE_POOL_MIN_IDLE = 0;
private static final Logger LOG = LoggerFactory.getLogger(DatabaseConfiguration.class);
/**
* Creates data source.
*
* @param dataSourceProperties Data source properties configured.
* @param appProperties the app properties
* @return Data source.
*/
@Bean(destroyMethod = "close")
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
@Primary
public DataSource dataSource(final DataSourceProperties dataSourceProperties,
final AppProperties appProperties) {
LOG.info("Configuring Datasource with url: {}, user: {}",
dataSourceProperties.getUrl(), dataSourceProperties.getUsername());
if (dataSourceProperties.getUrl() == null) {
LOG.error("Your Liquibase configuration is incorrect, please specify database URL!");
throw new ApplicationContextException("Data source is not configured correctly, please specify URL");
}
if (dataSourceProperties.getUsername() == null) {
LOG.error("Your Liquibase configuration is incorrect, please specify database user!");
throw new ApplicationContextException(
"Data source is not configured correctly, please specify database user");
}
if (dataSourceProperties.getPassword() == null) {
LOG.error("Your Liquibase configuration is incorrect, please specify database password!");
throw new ApplicationContextException(
"Data source is not configured correctly, "
+ "please specify database password");
}
PoolProperties config = new PoolProperties();
config.setDriverClassName(dataSourceProperties.getDriverClassName());
config.setUrl(dataSourceProperties.getUrl());
config.setUsername(dataSourceProperties.getUsername());
config.setPassword(dataSourceProperties.getPassword());
config.setInitialSize(appProperties.getDatasource().getInitialSize());
config.setMaxActive(appProperties.getDatasource().getMaxActive());
config.setTestOnBorrow(appProperties.getDatasource().isTestOnBorrow());
config.setValidationQuery(appProperties.getDatasource().getValidationQuery());
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource(config);
LOG.info("Data source is created: {}", dataSource);
return dataSource;
}
/**
* Create data source for Liquibase using dba user and password provided for "liquibase"
* in application.yml.
*
* @param dataSourceProperties Data source properties
* @param liquibaseProperties Liquibase properties.
* @param appProperties the app properties
* @return Data source for liquibase.
*/
@Bean(destroyMethod = "close")
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
public DataSource liquibaseDataSource(final DataSourceProperties dataSourceProperties,
final LiquibaseProperties liquibaseProperties, final AppProperties appProperties) {
LOG.info("Configuring Liquibase Datasource with url: {}, user: {}",
dataSourceProperties.getUrl(), liquibaseProperties.getUser());
/*
* This is needed for integration testing. When we run integration tests using SpringJUnit4ClassRunner, Spring
* uses
* H2DB if it is in the class path. In that case, we have to create pool for H2DB.
* Need to find a better solution for this.
*/
if (dataSourceProperties.getDriverClassName() != null
&& dataSourceProperties.getDriverClassName().startsWith("org.h2.")) {
return dataSource(dataSourceProperties, appProperties);
}
if (dataSourceProperties.getUrl() == null) {
LOG.error("Your Liquibase configuration is incorrect, please specify database URL!");
throw new ApplicationContextException("Liquibase is not configured correctly, please specify URL");
}
if (liquibaseProperties.getUser() == null) {
LOG.error("Your Liquibase configuration is incorrect, please specify database user!");
throw new ApplicationContextException(
"Liquibase is not configured correctly, please specify database user");
}
if (liquibaseProperties.getPassword() == null) {
LOG.error("Your Liquibase configuration is incorrect, please specify database password!");
throw new ApplicationContextException(
"Liquibase is not configured correctly, please specify database password");
}
PoolProperties config = new PoolProperties();
config.setDriverClassName(dataSourceProperties.getDriverClassName());
config.setUrl(dataSourceProperties.getUrl());
config.setUsername(liquibaseProperties.getUser());
config.setPassword(liquibaseProperties.getPassword());
// for liquibase pool, we dont need more than 1 connection
config.setInitialSize(LIQUIBASE_POOL_INIT_SIZE);
config.setMaxActive(LIQUIBASE_POOL_MAX_ACTIVE);
// for liquibase pool, we dont want any connections to linger around
config.setMaxIdle(LIQUIBASE_POOL_MAX_IDLE);
config.setMinIdle(LIQUIBASE_POOL_MIN_IDLE);
org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource(config);
LOG.info("Liquibase data source is created: {}", dataSource);
return dataSource;
}
/**
* Creates a liquibase instance.
*
* @param dataSource Data source to use for liquibase.
* @param dataSourceProperties Datasource properties.
* @param liquibaseProperties Liquibase properties.
* @return Liquibase instance to be used in spring.
*/
@Bean
public SpringLiquibase liquibase(@Qualifier("liquibaseDataSource") final DataSource dataSource,
final DataSourceProperties dataSourceProperties, final LiquibaseProperties liquibaseProperties) {
// Use liquibase.integration.spring.SpringLiquibase if you don't want Liquibase to start asynchronously
SpringLiquibase liquibase = new AsyncSpringLiquibase();
liquibase.setDataSource(dataSource);
liquibase.setChangeLog("classpath:config/liquibase/master.xml");
liquibase.setContexts(liquibaseProperties.getContexts());
liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema());
liquibase.setDropFirst(liquibaseProperties.isDropFirst());
liquibase.setShouldRun(liquibaseProperties.isEnabled());
return liquibase;
}
}
Благодарим за быстрый ответ. К сожалению, это изменение не помогло мне. Может быть, из-за того, как я настроил БД? Я обновил оригинальный пост с дополнительной информацией. – TechCrunch
Да, похоже, JHipster полностью игнорирует это свойство, и вы все равно не используете автоконфигурацию. Попробуйте добавить тег jhipster к вашему вопросу, чтобы привлечь больше внимания. –
Я использовал 'spring.datasource.url' вместо имени. Я отлично разбираюсь в том, что в тесте интеграции сейчас. Я хотел бы настроить это в конфигурации базы данных, но у меня есть два источника данных, подключающихся к одной и той же БД, но с разными разрешениями, и трудно обойти случайное значение для имени базы данных для обоих из них. Возможно, я мог бы попробовать статическую переменную в классе конфигурации базы данных. Спасибо за помощь. – TechCrunch