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 f57abf69ad..bec9d886d0 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 @@ -24,23 +24,17 @@ import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; import org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform; -import org.junit.After; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.springframework.beans.factory.BeanCreationException; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.test.City; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; -import org.springframework.boot.context.properties.source.ConfigurationPropertySources; -import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.orm.jpa.JpaTransactionManager; @@ -51,8 +45,6 @@ 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; @@ -65,172 +57,154 @@ import static org.assertj.core.api.Assertions.assertThat; */ public abstract class AbstractJpaAutoConfigurationTests { - @Rule - public ExpectedException expected = ExpectedException.none(); + private final Class autoConfiguredClass; - protected AnnotationConfigApplicationContext context; + private final ApplicationContextRunner contextRunner; - @After - public void close() { - if (this.context != null) { - this.context.close(); - } + protected AbstractJpaAutoConfigurationTests(Class autoConfiguredClass) { + this.autoConfiguredClass = autoConfiguredClass; + this.contextRunner = new ApplicationContextRunner() + .withPropertyValues("spring.datasource.generate-unique-name=true") + .withUserConfiguration(TestConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + TransactionAutoConfiguration.class, autoConfiguredClass)); } - protected abstract Class getAutoConfigureClass(); + protected ApplicationContextRunner contextRunner() { + return this.contextRunner; + } @Test - public void testNoDataSource() throws Exception { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.register(PropertyPlaceholderAutoConfiguration.class, - getAutoConfigureClass()); - this.expected.expect(BeanCreationException.class); - this.expected.expectMessage("No qualifying bean"); - this.expected.expectMessage("DataSource"); - context.refresh(); - context.close(); + public void dataSourceIsNotAvailable() { + new ApplicationContextRunner().withConfiguration(AutoConfigurations.of( + this.autoConfiguredClass)).run((context) -> { + assertThat(context).hasFailed(); + assertThat(context.getStartupFailure()) + .isInstanceOf(BeanCreationException.class); + assertThat(context.getStartupFailure()) + .hasMessageContaining("No qualifying bean"); + assertThat(context.getStartupFailure()).hasMessageContaining("DataSource"); + }); } @Test - public void testEntityManagerCreated() throws Exception { - load(); - assertThat(this.context.getBean(DataSource.class)).isNotNull(); - assertThat(this.context.getBean(JpaTransactionManager.class)).isNotNull(); + public void dataSourceIsCreatedWithDefaultConfig() { + this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(DataSource.class); + assertThat(context).hasSingleBean(JpaTransactionManager.class); + }); } @Test - public void testDataSourceTransactionManagerNotCreated() throws Exception { - load(new Class[0], - new Class[] { DataSourceTransactionManagerAutoConfiguration.class }); - assertThat(this.context.getBean(DataSource.class)).isNotNull(); - assertThat(this.context.getBean("transactionManager")) - .isInstanceOf(JpaTransactionManager.class); + public void jtaTransactionManagerTakesPrecedence() { + this.contextRunner.withConfiguration(AutoConfigurations.of( + DataSourceTransactionManagerAutoConfiguration.class)).run((context) -> { + assertThat(context).hasSingleBean(DataSource.class); + assertThat(context).hasSingleBean(JpaTransactionManager.class); + assertThat(context).getBean("transactionManager") + .isInstanceOf(JpaTransactionManager.class); + }); } @Test - public void testOpenEntityManagerInViewInterceptorCreated() throws Exception { - AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); - context.register(TestConfiguration.class, EmbeddedDataSourceConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); - context.refresh(); - assertThat(context.getBean(OpenEntityManagerInViewInterceptor.class)).isNotNull(); - context.close(); + public void openEntityManagerInViewInterceptorIsCreated() { + new WebApplicationContextRunner() + .withPropertyValues("spring.datasource.generate-unique-name=true") + .withUserConfiguration(TestConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + TransactionAutoConfiguration.class, this.autoConfiguredClass)) + .run((context) -> assertThat(context) + .hasSingleBean(OpenEntityManagerInViewInterceptor.class)); } @Test - public void testOpenEntityManagerInViewInterceptorNotRegisteredWhenFilterPresent() - throws Exception { - AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); - context.register(TestFilterConfiguration.class, - EmbeddedDataSourceConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); - context.refresh(); - assertThat(getInterceptorBeans(context).length).isEqualTo(0); - context.close(); + public void openEntityManagerInViewInterceptorIsNotRegisteredWhenFilterPresent() { + new WebApplicationContextRunner() + .withPropertyValues("spring.datasource.generate-unique-name=true") + .withUserConfiguration(TestFilterConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + TransactionAutoConfiguration.class, this.autoConfiguredClass)) + .run((context) -> assertThat(context) + .doesNotHaveBean(OpenEntityManagerInViewInterceptor.class)); } @Test - public void testOpenEntityManagerInViewInterceptorNotRegisteredWhenExplicitlyOff() - throws Exception { - AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); - TestPropertyValues.of("spring.jpa.open_in_view:false").applyTo(context); - context.register(TestConfiguration.class, EmbeddedDataSourceConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); - ConfigurationPropertySources.attach(context.getEnvironment()); - context.refresh(); - assertThat(getInterceptorBeans(context).length).isEqualTo(0); - context.close(); + public void openEntityManagerInViewInterceptorISNotRegisteredWhenExplicitlyOff() { + new WebApplicationContextRunner() + .withPropertyValues( + "spring.datasource.generate-unique-name=true", + "spring.jpa.open-in-view=false") + .withUserConfiguration(TestConfiguration.class) + .withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, + TransactionAutoConfiguration.class, this.autoConfiguredClass)) + .run((context) -> assertThat(context) + .doesNotHaveBean(OpenEntityManagerInViewInterceptor.class)); } @Test - public void customJpaProperties() throws Exception { - 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(); - assertThat(map.get("a")).isEqualTo("b"); - assertThat(map.get("c")).isEqualTo("d"); - assertThat(map.get("a.b")).isEqualTo("c"); + public void customJpaProperties() { + this.contextRunner.withPropertyValues("spring.jpa.properties.a:b", + "spring.jpa.properties.a.b:c", + "spring.jpa.properties.c:d").run((context) -> { + LocalContainerEntityManagerFactoryBean bean = context + .getBean(LocalContainerEntityManagerFactoryBean.class); + Map map = bean.getJpaPropertyMap(); + assertThat(map.get("a")).isEqualTo("b"); + assertThat(map.get("c")).isEqualTo("d"); + assertThat(map.get("a.b")).isEqualTo("c"); + }); } @Test public void usesManuallyDefinedLocalContainerEntityManagerFactoryBeanIfAvailable() { - load(TestConfigurationWithLocalContainerEntityManagerFactoryBean.class); - LocalContainerEntityManagerFactoryBean factoryBean = this.context - .getBean(LocalContainerEntityManagerFactoryBean.class); - Map map = factoryBean.getJpaPropertyMap(); - assertThat(map.get("configured")).isEqualTo("manually"); + this.contextRunner.withUserConfiguration( + TestConfigurationWithLocalContainerEntityManagerFactoryBean.class + ).run((context) -> { + LocalContainerEntityManagerFactoryBean factoryBean = context + .getBean(LocalContainerEntityManagerFactoryBean.class); + Map map = factoryBean.getJpaPropertyMap(); + assertThat(map.get("configured")).isEqualTo("manually"); + }); } @Test public void usesManuallyDefinedEntityManagerFactoryIfAvailable() { - load(TestConfigurationWithLocalContainerEntityManagerFactoryBean.class); - EntityManagerFactory factoryBean = this.context - .getBean(EntityManagerFactory.class); - Map map = factoryBean.getProperties(); - assertThat(map.get("configured")).isEqualTo("manually"); + this.contextRunner.withUserConfiguration( + TestConfigurationWithLocalContainerEntityManagerFactoryBean.class + ).run((context) -> { + EntityManagerFactory factoryBean = context + .getBean(EntityManagerFactory.class); + Map map = factoryBean.getProperties(); + assertThat(map.get("configured")).isEqualTo("manually"); + }); } @Test public void usesManuallyDefinedTransactionManagerBeanIfAvailable() { - load(TestConfigurationWithTransactionManager.class); - PlatformTransactionManager txManager = this.context - .getBean(PlatformTransactionManager.class); - assertThat(txManager).isInstanceOf(CustomJpaTransactionManager.class); + this.contextRunner.withUserConfiguration( + TestConfigurationWithTransactionManager.class + ).run((context) -> { + PlatformTransactionManager txManager = context + .getBean(PlatformTransactionManager.class); + assertThat(txManager).isInstanceOf(CustomJpaTransactionManager.class); + }); } @Test - public void customPersistenceUnitManager() throws Exception { - load(TestConfigurationWithCustomPersistenceUnitManager.class); - LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = this.context - .getBean(LocalContainerEntityManagerFactoryBean.class); - Field field = LocalContainerEntityManagerFactoryBean.class - .getDeclaredField("persistenceUnitManager"); - field.setAccessible(true); - assertThat(field.get(entityManagerFactoryBean)) - .isEqualTo(this.context.getBean(PersistenceUnitManager.class)); - } - - protected void load(String... environment) { - 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 load(Class[] configs, Class[] autoConfigs, - String... environment) { - load(configs, autoConfigs, null, environment); + public void customPersistenceUnitManager() { + this.contextRunner.withUserConfiguration( + TestConfigurationWithCustomPersistenceUnitManager.class + ).run((context) -> { + LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = context + .getBean(LocalContainerEntityManagerFactoryBean.class); + Field field = LocalContainerEntityManagerFactoryBean.class + .getDeclaredField("persistenceUnitManager"); + field.setAccessible(true); + assertThat(field.get(entityManagerFactoryBean)) + .isEqualTo(context.getBean(PersistenceUnitManager.class)); + }); } - protected void load(Class[] configs, Class[] autoConfigs, - ClassLoader classLoader, String... environment) { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - if (classLoader != null) { - ctx.setClassLoader(classLoader); - } - 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) { - return context.getBeanNamesForType(OpenEntityManagerInViewInterceptor.class); - } @Configuration @TestAutoConfigurationPackage(City.class) 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 ad6e40fdca..525ed6518a 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 @@ -34,12 +34,11 @@ import javax.transaction.TransactionManager; import javax.transaction.UserTransaction; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; @@ -65,95 +64,113 @@ import static org.mockito.Mockito.mock; public class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigurationTests { - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @Override - protected Class getAutoConfigureClass() { - return HibernateJpaAutoConfiguration.class; + public HibernateJpaAutoConfigurationTests() { + super(HibernateJpaAutoConfiguration.class); } @Test - public void testDataScriptWithMissingDdl() throws Exception { - this.thrown.expectMessage("ddl.sql"); - this.thrown.expectMessage("spring.datasource.schema"); - load("spring.datasource.data:classpath:/city.sql", + public void testDataScriptWithMissingDdl() { + contextRunner().withPropertyValues( + "spring.datasource.data:classpath:/city.sql", // Missing: - "spring.datasource.schema:classpath:/ddl.sql"); + "spring.datasource.schema:classpath:/ddl.sql").run((context) -> { + assertThat(context).hasFailed(); + assertThat(context.getStartupFailure()).hasMessageContaining("ddl.sql"); + assertThat(context.getStartupFailure()) + .hasMessageContaining("spring.datasource.schema"); + }); } @Test - public void testDataScript() throws Exception { + public void testDataScript() { // 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"); + contextRunner().withPropertyValues( + "spring.datasource.data:classpath:/city.sql").run((context) -> { + assertThat(context).hasFailed(); + assertThat(context.getStartupFailure()) + .isInstanceOf(BeanCreationException.class); + }); } @Test public void testDataScriptRunsEarly() { - load(new Class[] { TestInitializedJpaConfiguration.class }, null, - new HideDataScriptClassLoader(), "spring.jpa.show-sql=true", - "spring.jpa.hibernate.ddl-auto:create-drop", - "spring.datasource.data:classpath:/city.sql"); - assertThat(this.context.getBean(TestInitializedJpaConfiguration.class).called) - .isTrue(); + contextRunner().withUserConfiguration(TestInitializedJpaConfiguration.class) + .withClassLoader(new HideDataScriptClassLoader()) + .withPropertyValues("spring.jpa.show-sql=true", + "spring.jpa.hibernate.ddl-auto:create-drop", + "spring.datasource.data:classpath:/city.sql").run((context) -> + assertThat(context.getBean(TestInitializedJpaConfiguration.class).called) + .isTrue()); } @Test - public void testFlywaySwitchOffDdlAuto() throws Exception { - load(new Class[0], new Class[] { FlywayAutoConfiguration.class }, - "spring.datasource.initialize:false", - "spring.flyway.locations:classpath:db/city"); + public void testFlywaySwitchOffDdlAuto() { + contextRunner() + .withPropertyValues("spring.datasource.initialize:false", + "spring.flyway.locations:classpath:db/city") + .withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class)) + .run(context -> assertThat(context).hasNotFailed()); } @Test - public void testFlywayPlusValidation() throws Exception { - load(new Class[0], new Class[] { FlywayAutoConfiguration.class }, - "spring.datasource.initialize:false", - "spring.flyway.locations:classpath:db/city", - "spring.jpa.hibernate.ddl-auto:validate"); + public void testFlywayPlusValidation() { + contextRunner() + .withPropertyValues("spring.datasource.initialize:false", + "spring.flyway.locations:classpath:db/city", + "spring.jpa.hibernate.ddl-auto:validate") + .withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class)) + .run(context -> assertThat(context).hasNotFailed()); } @Test - public void testLiquibasePlusValidation() throws Exception { - load(new Class[0], new Class[] { LiquibaseAutoConfiguration.class }, - "spring.datasource.initialize:false", - "spring.liquibase.changeLog:classpath:db/changelog/db.changelog-city.yaml", - "spring.jpa.hibernate.ddl-auto:validate"); + public void testLiquibasePlusValidation() { + contextRunner() + .withPropertyValues("spring.datasource.initialize:false", + "spring.liquibase.changeLog:classpath:db/changelog/db.changelog-city.yaml", + "spring.jpa.hibernate.ddl-auto:validate") + .withConfiguration(AutoConfigurations.of(LiquibaseAutoConfiguration.class)) + .run(context -> assertThat(context).hasNotFailed()); } @Test - public void defaultJtaPlatform() throws Exception { - load(JtaAutoConfiguration.class); - Map jpaPropertyMap = this.context - .getBean(LocalContainerEntityManagerFactoryBean.class) - .getJpaPropertyMap(); - assertThat(jpaPropertyMap.get("hibernate.transaction.jta.platform")) - .isInstanceOf(SpringJtaPlatform.class); + public void jtaDefaultPlatform() { + contextRunner().withConfiguration(AutoConfigurations.of( + JtaAutoConfiguration.class)).run((context) -> { + Map jpaPropertyMap = context + .getBean(LocalContainerEntityManagerFactoryBean.class) + .getJpaPropertyMap(); + assertThat(jpaPropertyMap.get("hibernate.transaction.jta.platform")) + .isInstanceOf(SpringJtaPlatform.class); + }); } @Test - public void testCustomJtaPlatform() throws Exception { - load(JtaAutoConfiguration.class, - "spring.jpa.properties.hibernate.transaction.jta.platform:" - + TestJtaPlatform.class.getName()); - Map jpaPropertyMap = this.context - .getBean(LocalContainerEntityManagerFactoryBean.class) - .getJpaPropertyMap(); - assertThat((String) jpaPropertyMap.get("hibernate.transaction.jta.platform")) - .isEqualTo(TestJtaPlatform.class.getName()); + public void jtaCustomPlatform() { + contextRunner() + .withPropertyValues( + "spring.jpa.properties.hibernate.transaction.jta.platform:" + + TestJtaPlatform.class.getName()) + .withConfiguration(AutoConfigurations.of( + JtaAutoConfiguration.class)).run((context) -> { + Map jpaPropertyMap = context + .getBean(LocalContainerEntityManagerFactoryBean.class) + .getJpaPropertyMap(); + assertThat((String) jpaPropertyMap.get("hibernate.transaction.jta.platform")) + .isEqualTo(TestJtaPlatform.class.getName()); + }); } @Test - public void testCustomJpaTransactionManagerUsingProperties() throws Exception { - 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); - assertThat(transactionManager.isRollbackOnCommitFailure()).isTrue(); + public void jtaCustomTransactionManagerUsingProperties() { + contextRunner().withPropertyValues("spring.transaction.default-timeout:30", + "spring.transaction.rollback-on-commit-failure:true").run((context) -> { + JpaTransactionManager transactionManager = context + .getBean(JpaTransactionManager.class); + assertThat(transactionManager.getDefaultTimeout()).isEqualTo(30); + assertThat(transactionManager.isRollbackOnCommitFailure()).isTrue(); + }); } @Configuration