Clean HibernateJpaAutoConfigurationTests

This commit makes sure that each test runs with the proper datasource
auto-configuration and with an isolated embedded database. This allows
to restrict each test to only what it is supposed to do (rather than
disabling initialization to work around the fact that database is not
in a proper state because it is shared).

Closes gh-9579
pull/9554/head
Stephane Nicoll 8 years ago
parent 235daf839f
commit 885e29934b

@ -51,6 +51,7 @@ import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter; import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor; import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -60,44 +61,46 @@ import static org.assertj.core.api.Assertions.assertThat;
* *
* @author Phillip Webb * @author Phillip Webb
* @author Dave Syer * @author Dave Syer
* @author Stephane Nicoll
*/ */
public abstract class AbstractJpaAutoConfigurationTests { public abstract class AbstractJpaAutoConfigurationTests {
@Rule @Rule
public ExpectedException expected = ExpectedException.none(); public ExpectedException expected = ExpectedException.none();
protected AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); protected AnnotationConfigApplicationContext context;
@After @After
public void close() { public void close() {
this.context.close(); if (this.context != null) {
this.context.close();
}
} }
protected abstract Class<?> getAutoConfigureClass(); protected abstract Class<?> getAutoConfigureClass();
@Test @Test
public void testNoDataSource() throws Exception { public void testNoDataSource() throws Exception {
this.context.register(PropertyPlaceholderAutoConfiguration.class, AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(PropertyPlaceholderAutoConfiguration.class,
getAutoConfigureClass()); getAutoConfigureClass());
this.expected.expect(BeanCreationException.class); this.expected.expect(BeanCreationException.class);
this.expected.expectMessage("No qualifying bean"); this.expected.expectMessage("No qualifying bean");
this.expected.expectMessage("DataSource"); this.expected.expectMessage("DataSource");
this.context.refresh(); ctx.refresh();
} }
@Test @Test
public void testEntityManagerCreated() throws Exception { public void testEntityManagerCreated() throws Exception {
setupTestConfiguration(); load();
this.context.refresh();
assertThat(this.context.getBean(DataSource.class)).isNotNull(); assertThat(this.context.getBean(DataSource.class)).isNotNull();
assertThat(this.context.getBean(JpaTransactionManager.class)).isNotNull(); assertThat(this.context.getBean(JpaTransactionManager.class)).isNotNull();
} }
@Test @Test
public void testDataSourceTransactionManagerNotCreated() throws Exception { public void testDataSourceTransactionManagerNotCreated() throws Exception {
this.context.register(DataSourceTransactionManagerAutoConfiguration.class); load(new Class<?>[0],
setupTestConfiguration(); new Class<?>[] { DataSourceTransactionManagerAutoConfiguration.class });
this.context.refresh();
assertThat(this.context.getBean(DataSource.class)).isNotNull(); assertThat(this.context.getBean(DataSource.class)).isNotNull();
assertThat(this.context.getBean("transactionManager")) assertThat(this.context.getBean("transactionManager"))
.isInstanceOf(JpaTransactionManager.class); .isInstanceOf(JpaTransactionManager.class);
@ -140,10 +143,8 @@ public abstract class AbstractJpaAutoConfigurationTests {
@Test @Test
public void customJpaProperties() throws Exception { public void customJpaProperties() throws Exception {
TestPropertyValues.of("spring.jpa.properties.a:b", "spring.jpa.properties.a.b:c", load("spring.jpa.properties.a:b", "spring.jpa.properties.a.b:c",
"spring.jpa.properties.c:d").applyTo(this.context); "spring.jpa.properties.c:d");
setupTestConfiguration();
this.context.refresh();
LocalContainerEntityManagerFactoryBean bean = this.context LocalContainerEntityManagerFactoryBean bean = this.context
.getBean(LocalContainerEntityManagerFactoryBean.class); .getBean(LocalContainerEntityManagerFactoryBean.class);
Map<String, Object> map = bean.getJpaPropertyMap(); Map<String, Object> map = bean.getJpaPropertyMap();
@ -154,10 +155,7 @@ public abstract class AbstractJpaAutoConfigurationTests {
@Test @Test
public void usesManuallyDefinedLocalContainerEntityManagerFactoryBeanIfAvailable() { public void usesManuallyDefinedLocalContainerEntityManagerFactoryBeanIfAvailable() {
TestPropertyValues.of("spring.datasource.initialize:false"); load(TestConfigurationWithLocalContainerEntityManagerFactoryBean.class);
setupTestConfiguration(
TestConfigurationWithLocalContainerEntityManagerFactoryBean.class);
this.context.refresh();
LocalContainerEntityManagerFactoryBean factoryBean = this.context LocalContainerEntityManagerFactoryBean factoryBean = this.context
.getBean(LocalContainerEntityManagerFactoryBean.class); .getBean(LocalContainerEntityManagerFactoryBean.class);
Map<String, Object> map = factoryBean.getJpaPropertyMap(); Map<String, Object> map = factoryBean.getJpaPropertyMap();
@ -166,9 +164,7 @@ public abstract class AbstractJpaAutoConfigurationTests {
@Test @Test
public void usesManuallyDefinedEntityManagerFactoryIfAvailable() { public void usesManuallyDefinedEntityManagerFactoryIfAvailable() {
TestPropertyValues.of("spring.datasource.initialize:false").applyTo(this.context); load(TestConfigurationWithLocalContainerEntityManagerFactoryBean.class);
setupTestConfiguration(TestConfigurationWithEntityManagerFactory.class);
this.context.refresh();
EntityManagerFactory factoryBean = this.context EntityManagerFactory factoryBean = this.context
.getBean(EntityManagerFactory.class); .getBean(EntityManagerFactory.class);
Map<String, Object> map = factoryBean.getProperties(); Map<String, Object> map = factoryBean.getProperties();
@ -177,8 +173,7 @@ public abstract class AbstractJpaAutoConfigurationTests {
@Test @Test
public void usesManuallyDefinedTransactionManagerBeanIfAvailable() { public void usesManuallyDefinedTransactionManagerBeanIfAvailable() {
setupTestConfiguration(TestConfigurationWithTransactionManager.class); load(TestConfigurationWithTransactionManager.class);
this.context.refresh();
PlatformTransactionManager txManager = this.context PlatformTransactionManager txManager = this.context
.getBean(PlatformTransactionManager.class); .getBean(PlatformTransactionManager.class);
assertThat(txManager).isInstanceOf(CustomJpaTransactionManager.class); assertThat(txManager).isInstanceOf(CustomJpaTransactionManager.class);
@ -186,8 +181,7 @@ public abstract class AbstractJpaAutoConfigurationTests {
@Test @Test
public void customPersistenceUnitManager() throws Exception { public void customPersistenceUnitManager() throws Exception {
setupTestConfiguration(TestConfigurationWithCustomPersistenceUnitManager.class); load(TestConfigurationWithCustomPersistenceUnitManager.class);
this.context.refresh();
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = this.context LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = this.context
.getBean(LocalContainerEntityManagerFactoryBean.class); .getBean(LocalContainerEntityManagerFactoryBean.class);
Field field = LocalContainerEntityManagerFactoryBean.class Field field = LocalContainerEntityManagerFactoryBean.class
@ -197,14 +191,32 @@ public abstract class AbstractJpaAutoConfigurationTests {
.isEqualTo(this.context.getBean(PersistenceUnitManager.class)); .isEqualTo(this.context.getBean(PersistenceUnitManager.class));
} }
protected void setupTestConfiguration() { protected void load(String... environment) {
setupTestConfiguration(TestConfiguration.class); load(new Class<?>[0], new Class<?>[0], environment);
}
protected void load(Class<?> config, String... environment) {
Class<?>[] configs = config != null ? new Class<?>[] { config } : null;
load(configs, new Class<?>[0], environment);
} }
protected void setupTestConfiguration(Class<?> configClass) { protected void load(Class<?>[] configs, Class<?>[] autoConfigs, String... environment) {
this.context.register(configClass, EmbeddedDataSourceConfiguration.class, AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
TestPropertyValues.of(environment)
.and("spring.datasource.generate-unique-name", "true")
.applyTo(ctx);
ctx.register(TestConfiguration.class);
if (!ObjectUtils.isEmpty(configs)) {
ctx.register(configs);
}
ctx.register(
DataSourceAutoConfiguration.class, TransactionAutoConfiguration.class, DataSourceAutoConfiguration.class, TransactionAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass());
if (!ObjectUtils.isEmpty(autoConfigs)) {
ctx.register(autoConfigs);
}
ctx.refresh();
this.context = ctx;
} }
private String[] getInterceptorBeans(ApplicationContext context) { private String[] getInterceptorBeans(ApplicationContext context) {

@ -18,7 +18,6 @@ package org.springframework.boot.autoconfigure.orm.jpa;
import java.util.Map; import java.util.Map;
import javax.sql.DataSource;
import javax.transaction.Synchronization; import javax.transaction.Synchronization;
import javax.transaction.SystemException; import javax.transaction.SystemException;
import javax.transaction.Transaction; import javax.transaction.Transaction;
@ -35,8 +34,6 @@ import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
import org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration; import org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration;
import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform; import org.springframework.boot.orm.jpa.hibernate.SpringJtaPlatform;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@ -50,6 +47,7 @@ import static org.mockito.Mockito.mock;
* @author Phillip Webb * @author Phillip Webb
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Kazuki Shimizu * @author Kazuki Shimizu
* @author Stephane Nicoll
*/ */
public class HibernateJpaAutoConfigurationTests public class HibernateJpaAutoConfigurationTests
extends AbstractJpaAutoConfigurationTests { extends AbstractJpaAutoConfigurationTests {
@ -64,55 +62,40 @@ public class HibernateJpaAutoConfigurationTests
@Test @Test
public void testDataScriptWithMissingDdl() throws Exception { public void testDataScriptWithMissingDdl() throws Exception {
TestPropertyValues
.of("spring.datasource.data:classpath:/city.sql",
// Missing:
"spring.datasource.schema:classpath:/ddl.sql")
.applyTo(this.context);
setupTestConfiguration();
this.thrown.expectMessage("ddl.sql"); this.thrown.expectMessage("ddl.sql");
this.thrown.expectMessage("spring.datasource.schema"); this.thrown.expectMessage("spring.datasource.schema");
this.context.refresh(); load("spring.datasource.data:classpath:/city.sql",
// Missing:
"spring.datasource.schema:classpath:/ddl.sql");
} }
// This can't succeed because the data SQL is executed immediately after the schema @Test
// and Hibernate hasn't initialized yet at that point
@Test(expected = BeanCreationException.class)
public void testDataScript() throws Exception { public void testDataScript() throws Exception {
TestPropertyValues.of("spring.datasource.data:classpath:/city.sql") // This can't succeed because the data SQL is executed immediately after the schema
.applyTo(this.context); // and Hibernate hasn't initialized yet at that point
setupTestConfiguration(); this.thrown.expect(BeanCreationException.class);
this.context.refresh(); load("spring.datasource.data:classpath:/city.sql");
assertThat(new JdbcTemplate(this.context.getBean(DataSource.class))
.queryForObject("SELECT COUNT(*) from CITY", Integer.class)).isEqualTo(1);
} }
@Test @Test
public void testFlywayPlusValidation() throws Exception { public void testFlywayPlusValidation() throws Exception {
TestPropertyValues.of("spring.datasource.initialize:false", load(new Class<?>[0], new Class<?>[] { FlywayAutoConfiguration.class },
"spring.datasource.initialize:false",
"flyway.locations:classpath:db/city", "flyway.locations:classpath:db/city",
"spring.jpa.hibernate.ddl-auto:validate").applyTo(this.context); "spring.jpa.hibernate.ddl-auto:validate");
setupTestConfiguration();
this.context.register(FlywayAutoConfiguration.class);
this.context.refresh();
} }
@Test @Test
public void testLiquibasePlusValidation() throws Exception { public void testLiquibasePlusValidation() throws Exception {
TestPropertyValues.of("spring.datasource.initialize:false", load(new Class<?>[0], new Class<?>[] { LiquibaseAutoConfiguration.class },
"spring.datasource.initialize:false",
"liquibase.changeLog:classpath:db/changelog/db.changelog-city.yaml", "liquibase.changeLog:classpath:db/changelog/db.changelog-city.yaml",
"spring.jpa.hibernate.ddl-auto:validate").applyTo(this.context); "spring.jpa.hibernate.ddl-auto:validate");
setupTestConfiguration();
this.context.register(LiquibaseAutoConfiguration.class);
this.context.refresh();
} }
@Test @Test
public void defaultJtaPlatform() throws Exception { public void defaultJtaPlatform() throws Exception {
this.context.register(JtaAutoConfiguration.class); load(JtaAutoConfiguration.class);
setupTestConfiguration();
this.context.refresh();
Map<String, Object> jpaPropertyMap = this.context Map<String, Object> jpaPropertyMap = this.context
.getBean(LocalContainerEntityManagerFactoryBean.class) .getBean(LocalContainerEntityManagerFactoryBean.class)
.getJpaPropertyMap(); .getJpaPropertyMap();
@ -122,11 +105,9 @@ public class HibernateJpaAutoConfigurationTests
@Test @Test
public void testCustomJtaPlatform() throws Exception { public void testCustomJtaPlatform() throws Exception {
TestPropertyValues.of("spring.jpa.properties.hibernate.transaction.jta.platform:" load(JtaAutoConfiguration.class,
+ TestJtaPlatform.class.getName()).applyTo(this.context); "spring.jpa.properties.hibernate.transaction.jta.platform:"
this.context.register(JtaAutoConfiguration.class); + TestJtaPlatform.class.getName());
setupTestConfiguration();
this.context.refresh();
Map<String, Object> jpaPropertyMap = this.context Map<String, Object> jpaPropertyMap = this.context
.getBean(LocalContainerEntityManagerFactoryBean.class) .getBean(LocalContainerEntityManagerFactoryBean.class)
.getJpaPropertyMap(); .getJpaPropertyMap();
@ -136,12 +117,8 @@ public class HibernateJpaAutoConfigurationTests
@Test @Test
public void testCustomJpaTransactionManagerUsingProperties() throws Exception { public void testCustomJpaTransactionManagerUsingProperties() throws Exception {
TestPropertyValues load("spring.transaction.default-timeout:30",
.of("spring.transaction.default-timeout:30", "spring.transaction.rollback-on-commit-failure:true");
"spring.transaction.rollback-on-commit-failure:true")
.applyTo(this.context);
setupTestConfiguration();
this.context.refresh();
JpaTransactionManager transactionManager = this.context JpaTransactionManager transactionManager = this.context
.getBean(JpaTransactionManager.class); .getBean(JpaTransactionManager.class);
assertThat(transactionManager.getDefaultTimeout()).isEqualTo(30); assertThat(transactionManager.getDefaultTimeout()).isEqualTo(30);

Loading…
Cancel
Save