From 885e29934b082682c5a5f2095188539353be39ec Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 22 Jun 2017 17:47:35 +0200 Subject: [PATCH] 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 --- .../AbstractJpaAutoConfigurationTests.java | 68 +++++++++++-------- .../HibernateJpaAutoConfigurationTests.java | 65 ++++++------------ 2 files changed, 61 insertions(+), 72 deletions(-) diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java index 97fc110849..8f70a4b065 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java @@ -51,6 +51,7 @@ import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager; import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter; import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor; import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.util.ObjectUtils; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import static org.assertj.core.api.Assertions.assertThat; @@ -60,44 +61,46 @@ import static org.assertj.core.api.Assertions.assertThat; * * @author Phillip Webb * @author Dave Syer + * @author Stephane Nicoll */ public abstract class AbstractJpaAutoConfigurationTests { @Rule public ExpectedException expected = ExpectedException.none(); - protected AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + protected AnnotationConfigApplicationContext context; @After public void close() { - this.context.close(); + if (this.context != null) { + this.context.close(); + } } protected abstract Class getAutoConfigureClass(); @Test public void testNoDataSource() throws Exception { - this.context.register(PropertyPlaceholderAutoConfiguration.class, + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); this.expected.expect(BeanCreationException.class); this.expected.expectMessage("No qualifying bean"); this.expected.expectMessage("DataSource"); - this.context.refresh(); + ctx.refresh(); } @Test public void testEntityManagerCreated() throws Exception { - setupTestConfiguration(); - this.context.refresh(); + load(); assertThat(this.context.getBean(DataSource.class)).isNotNull(); assertThat(this.context.getBean(JpaTransactionManager.class)).isNotNull(); } @Test public void testDataSourceTransactionManagerNotCreated() throws Exception { - this.context.register(DataSourceTransactionManagerAutoConfiguration.class); - setupTestConfiguration(); - this.context.refresh(); + load(new Class[0], + new Class[] { DataSourceTransactionManagerAutoConfiguration.class }); assertThat(this.context.getBean(DataSource.class)).isNotNull(); assertThat(this.context.getBean("transactionManager")) .isInstanceOf(JpaTransactionManager.class); @@ -140,10 +143,8 @@ public abstract class AbstractJpaAutoConfigurationTests { @Test public void customJpaProperties() throws Exception { - TestPropertyValues.of("spring.jpa.properties.a:b", "spring.jpa.properties.a.b:c", - "spring.jpa.properties.c:d").applyTo(this.context); - setupTestConfiguration(); - this.context.refresh(); + load("spring.jpa.properties.a:b", "spring.jpa.properties.a.b:c", + "spring.jpa.properties.c:d"); LocalContainerEntityManagerFactoryBean bean = this.context .getBean(LocalContainerEntityManagerFactoryBean.class); Map map = bean.getJpaPropertyMap(); @@ -154,10 +155,7 @@ public abstract class AbstractJpaAutoConfigurationTests { @Test public void usesManuallyDefinedLocalContainerEntityManagerFactoryBeanIfAvailable() { - TestPropertyValues.of("spring.datasource.initialize:false"); - setupTestConfiguration( - TestConfigurationWithLocalContainerEntityManagerFactoryBean.class); - this.context.refresh(); + load(TestConfigurationWithLocalContainerEntityManagerFactoryBean.class); LocalContainerEntityManagerFactoryBean factoryBean = this.context .getBean(LocalContainerEntityManagerFactoryBean.class); Map map = factoryBean.getJpaPropertyMap(); @@ -166,9 +164,7 @@ public abstract class AbstractJpaAutoConfigurationTests { @Test public void usesManuallyDefinedEntityManagerFactoryIfAvailable() { - TestPropertyValues.of("spring.datasource.initialize:false").applyTo(this.context); - setupTestConfiguration(TestConfigurationWithEntityManagerFactory.class); - this.context.refresh(); + load(TestConfigurationWithLocalContainerEntityManagerFactoryBean.class); EntityManagerFactory factoryBean = this.context .getBean(EntityManagerFactory.class); Map map = factoryBean.getProperties(); @@ -177,8 +173,7 @@ public abstract class AbstractJpaAutoConfigurationTests { @Test public void usesManuallyDefinedTransactionManagerBeanIfAvailable() { - setupTestConfiguration(TestConfigurationWithTransactionManager.class); - this.context.refresh(); + load(TestConfigurationWithTransactionManager.class); PlatformTransactionManager txManager = this.context .getBean(PlatformTransactionManager.class); assertThat(txManager).isInstanceOf(CustomJpaTransactionManager.class); @@ -186,8 +181,7 @@ public abstract class AbstractJpaAutoConfigurationTests { @Test public void customPersistenceUnitManager() throws Exception { - setupTestConfiguration(TestConfigurationWithCustomPersistenceUnitManager.class); - this.context.refresh(); + load(TestConfigurationWithCustomPersistenceUnitManager.class); LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = this.context .getBean(LocalContainerEntityManagerFactoryBean.class); Field field = LocalContainerEntityManagerFactoryBean.class @@ -197,14 +191,32 @@ public abstract class AbstractJpaAutoConfigurationTests { .isEqualTo(this.context.getBean(PersistenceUnitManager.class)); } - protected void setupTestConfiguration() { - setupTestConfiguration(TestConfiguration.class); + protected void load(String... environment) { + load(new Class[0], new Class[0], environment); } - protected void setupTestConfiguration(Class configClass) { - this.context.register(configClass, EmbeddedDataSourceConfiguration.class, + protected void load(Class config, String... environment) { + Class[] configs = config != null ? new Class[] { config } : null; + load(configs, new Class[0], environment); + } + + protected void load(Class[] configs, Class[] autoConfigs, String... environment) { + 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, PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); + if (!ObjectUtils.isEmpty(autoConfigs)) { + ctx.register(autoConfigs); + } + ctx.refresh(); + this.context = ctx; } private String[] getInterceptorBeans(ApplicationContext context) { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java index fa82073f35..834ce23627 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfigurationTests.java @@ -18,7 +18,6 @@ package org.springframework.boot.autoconfigure.orm.jpa; import java.util.Map; -import javax.sql.DataSource; import javax.transaction.Synchronization; import javax.transaction.SystemException; 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.transaction.jta.JtaAutoConfiguration; 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.LocalContainerEntityManagerFactoryBean; @@ -50,6 +47,7 @@ import static org.mockito.Mockito.mock; * @author Phillip Webb * @author Andy Wilkinson * @author Kazuki Shimizu + * @author Stephane Nicoll */ public class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTests { @@ -64,55 +62,40 @@ public class HibernateJpaAutoConfigurationTests @Test 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("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 - // and Hibernate hasn't initialized yet at that point - @Test(expected = BeanCreationException.class) + @Test public void testDataScript() throws Exception { - TestPropertyValues.of("spring.datasource.data:classpath:/city.sql") - .applyTo(this.context); - setupTestConfiguration(); - this.context.refresh(); - assertThat(new JdbcTemplate(this.context.getBean(DataSource.class)) - .queryForObject("SELECT COUNT(*) from CITY", Integer.class)).isEqualTo(1); + // This can't succeed because the data SQL is executed immediately after the schema + // and Hibernate hasn't initialized yet at that point + this.thrown.expect(BeanCreationException.class); + load("spring.datasource.data:classpath:/city.sql"); } @Test 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", - "spring.jpa.hibernate.ddl-auto:validate").applyTo(this.context); - setupTestConfiguration(); - this.context.register(FlywayAutoConfiguration.class); - this.context.refresh(); + "spring.jpa.hibernate.ddl-auto:validate"); } @Test 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", - "spring.jpa.hibernate.ddl-auto:validate").applyTo(this.context); - setupTestConfiguration(); - this.context.register(LiquibaseAutoConfiguration.class); - this.context.refresh(); + "spring.jpa.hibernate.ddl-auto:validate"); } @Test public void defaultJtaPlatform() throws Exception { - this.context.register(JtaAutoConfiguration.class); - setupTestConfiguration(); - this.context.refresh(); + load(JtaAutoConfiguration.class); Map jpaPropertyMap = this.context .getBean(LocalContainerEntityManagerFactoryBean.class) .getJpaPropertyMap(); @@ -122,11 +105,9 @@ public class HibernateJpaAutoConfigurationTests @Test public void testCustomJtaPlatform() throws Exception { - TestPropertyValues.of("spring.jpa.properties.hibernate.transaction.jta.platform:" - + TestJtaPlatform.class.getName()).applyTo(this.context); - this.context.register(JtaAutoConfiguration.class); - setupTestConfiguration(); - this.context.refresh(); + load(JtaAutoConfiguration.class, + "spring.jpa.properties.hibernate.transaction.jta.platform:" + + TestJtaPlatform.class.getName()); Map jpaPropertyMap = this.context .getBean(LocalContainerEntityManagerFactoryBean.class) .getJpaPropertyMap(); @@ -136,12 +117,8 @@ public class HibernateJpaAutoConfigurationTests @Test public void testCustomJpaTransactionManagerUsingProperties() throws Exception { - TestPropertyValues - .of("spring.transaction.default-timeout:30", - "spring.transaction.rollback-on-commit-failure:true") - .applyTo(this.context); - setupTestConfiguration(); - this.context.refresh(); + load("spring.transaction.default-timeout:30", + "spring.transaction.rollback-on-commit-failure:true"); JpaTransactionManager transactionManager = this.context .getBean(JpaTransactionManager.class); assertThat(transactionManager.getDefaultTimeout()).isEqualTo(30);