From ef5c2afcc9b055c3f967cde56c7bc42fca50cf42 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 7 Jul 2017 11:11:02 +0100 Subject: [PATCH] Polish --- ...HealthIndicatorAutoConfigurationTests.java | 8 +- .../cache/CacheAutoConfigurationTests.java | 6 +- ...HazelcastAutoConfigurationClientTests.java | 6 +- ...HazelcastAutoConfigurationServerTests.java | 6 +- .../HazelcastAutoConfigurationTests.java | 4 +- .../DataSourceAutoConfigurationTests.java | 6 +- .../jms/JmsAutoConfigurationTests.java | 5 +- .../ActiveMQAutoConfigurationTests.java | 5 +- .../ArtemisAutoConfigurationTests.java | 5 +- .../HttpHandlerAutoConfigurationTests.java | 6 +- .../servlet/WebMvcAutoConfigurationTests.java | 18 +- .../WebServicesAutoConfigurationTests.java | 6 +- .../TestDatabaseAutoConfigurationTests.java | 6 +- ...abaseAutoConfigurationNoEmbeddedTests.java | 6 +- .../test/context/AbstractContextLoader.java | 321 ++++++++++++++++++ .../boot/test/context/ContextConsumer.java | 5 +- .../boot/test/context/ContextLoader.java | 45 ++- .../context/ReactiveWebContextLoader.java | 39 +++ .../test/context/ServletWebContextLoader.java | 50 +++ .../test/context/StandardContextLoader.java | 277 +-------------- .../test/context/WebMvcContextConsumer.java | 40 +++ .../context/StandardContextLoaderTests.java | 7 +- 22 files changed, 528 insertions(+), 349 deletions(-) create mode 100644 spring-boot-test/src/main/java/org/springframework/boot/test/context/AbstractContextLoader.java create mode 100644 spring-boot-test/src/main/java/org/springframework/boot/test/context/ReactiveWebContextLoader.java create mode 100644 spring-boot-test/src/main/java/org/springframework/boot/test/context/ServletWebContextLoader.java create mode 100644 spring-boot-test/src/main/java/org/springframework/boot/test/context/WebMvcContextConsumer.java diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java index 5b6192d15e..3d20aaa05c 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/HealthIndicatorAutoConfigurationTests.java @@ -58,7 +58,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.ContextConsumer; import org.springframework.boot.test.context.ContextLoader; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.boot.test.context.StandardContextLoader; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.cassandra.core.CassandraOperations; @@ -80,8 +80,8 @@ import static org.mockito.Mockito.mock; */ public class HealthIndicatorAutoConfigurationTests { - public final ContextLoader contextLoader = ContextLoader - .standard().autoConfig(HealthIndicatorAutoConfiguration.class, + public final StandardContextLoader contextLoader = ContextLoader.standard() + .autoConfig(HealthIndicatorAutoConfiguration.class, ManagementServerProperties.class); @Test @@ -380,7 +380,7 @@ public class HealthIndicatorAutoConfigurationTests { .load(hasSingleHealthIndicator(ApplicationHealthIndicator.class)); } - private ContextConsumer hasSingleHealthIndicator( + private ContextConsumer hasSingleHealthIndicator( Class type) { return context -> { Map beans = context diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java index 0605e988f4..80de12f0cc 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java @@ -56,6 +56,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.autoconfigure.cache.support.MockCachingProvider; import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration; import org.springframework.boot.test.context.ContextLoader; +import org.springframework.boot.test.context.StandardContextLoader; import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions; import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner; import org.springframework.cache.Cache; @@ -73,7 +74,6 @@ import org.springframework.cache.jcache.JCacheCacheManager; import org.springframework.cache.support.NoOpCacheManager; import org.springframework.cache.support.SimpleCacheManager; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -101,8 +101,8 @@ public class CacheAutoConfigurationTests { @Rule public final ExpectedException thrown = ExpectedException.none(); - private final ContextLoader contextLoader = ContextLoader - .standard().autoConfig(CacheAutoConfiguration.class); + private final StandardContextLoader contextLoader = ContextLoader.standard() + .autoConfig(CacheAutoConfiguration.class); @Test public void noEnableCaching() { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationClientTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationClientTests.java index 121db866bb..2759ff0c31 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationClientTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationClientTests.java @@ -29,7 +29,7 @@ import org.junit.Test; import org.springframework.beans.factory.BeanCreationException; import org.springframework.boot.test.context.ContextLoader; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.boot.test.context.StandardContextLoader; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -60,8 +60,8 @@ public class HazelcastAutoConfigurationClientTests { } } - private final ContextLoader contextLoader = ContextLoader - .standard().autoConfig(HazelcastAutoConfiguration.class); + private final StandardContextLoader contextLoader = ContextLoader.standard() + .autoConfig(HazelcastAutoConfiguration.class); @Test public void systemProperty() throws IOException { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationServerTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationServerTests.java index 54ffc96c9e..500b13d350 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationServerTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationServerTests.java @@ -28,9 +28,9 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.BeanCreationException; import org.springframework.boot.test.context.ContextLoader; +import org.springframework.boot.test.context.StandardContextLoader; import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions; import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; @@ -46,8 +46,8 @@ import static org.assertj.core.api.Assertions.assertThat; @ClassPathExclusions("hazelcast-client-*.jar") public class HazelcastAutoConfigurationServerTests { - private final ContextLoader contextLoader = ContextLoader - .standard().autoConfig(HazelcastAutoConfiguration.class); + private final StandardContextLoader contextLoader = ContextLoader.standard() + .autoConfig(HazelcastAutoConfiguration.class); @Test public void defaultConfigFile() throws IOException { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationTests.java index e62b26fd96..151cb7c27d 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationTests.java @@ -22,7 +22,7 @@ import com.hazelcast.core.HazelcastInstance; import org.junit.Test; import org.springframework.boot.test.context.ContextLoader; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.boot.test.context.StandardContextLoader; import org.springframework.core.io.ClassPathResource; import static org.assertj.core.api.Assertions.assertThat; @@ -34,7 +34,7 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class HazelcastAutoConfigurationTests { - private final ContextLoader contextLoader = ContextLoader + private final StandardContextLoader contextLoader = ContextLoader .standard().autoConfig(HazelcastAutoConfiguration.class); @Test diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java index b1b8f86766..46c89c879d 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfigurationTests.java @@ -41,7 +41,7 @@ import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.test.context.ContextConsumer; import org.springframework.boot.test.context.ContextLoader; import org.springframework.boot.test.context.HidePackagesClassLoader; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.boot.test.context.StandardContextLoader; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; @@ -58,7 +58,7 @@ import static org.mockito.Mockito.mock; */ public class DataSourceAutoConfigurationTests { - private final ContextLoader contextLoader = ContextLoader + private final StandardContextLoader contextLoader = ContextLoader .standard().autoConfig(DataSourceAutoConfiguration.class) .env("spring.datasource.initialize=false", "spring.datasource.url:jdbc:hsqldb:mem:testdb-" @@ -185,7 +185,7 @@ public class DataSourceAutoConfigurationTests { .load(testExplicitType()); } - private ContextConsumer testExplicitType() { + private ContextConsumer testExplicitType() { return context -> { assertThat(context.getBeansOfType(DataSource.class)).hasSize(1); DataSource bean = context.getBean(DataSource.class); diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java index fec974b911..cf1ff4e87c 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/JmsAutoConfigurationTests.java @@ -28,7 +28,7 @@ import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration; import org.springframework.boot.test.context.ContextLoader; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.boot.test.context.StandardContextLoader; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @@ -62,8 +62,7 @@ public class JmsAutoConfigurationTests { private static final String ACTIVEMQ_NETWORK_URL = "tcp://localhost:61616"; - private final ContextLoader contextLoader = ContextLoader - .standard() + private final StandardContextLoader contextLoader = ContextLoader.standard() .autoConfig(ActiveMQAutoConfiguration.class, JmsAutoConfiguration.class); @Test diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java index 32faaf6ae6..ab6630b84c 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQAutoConfigurationTests.java @@ -25,7 +25,7 @@ import org.junit.Test; import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration; import org.springframework.boot.test.context.ContextLoader; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.boot.test.context.StandardContextLoader; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -42,8 +42,7 @@ import static org.mockito.Mockito.mockingDetails; */ public class ActiveMQAutoConfigurationTests { - private final ContextLoader contextLoader = ContextLoader - .standard() + private final StandardContextLoader contextLoader = ContextLoader.standard() .autoConfig(ActiveMQAutoConfiguration.class, JmsAutoConfiguration.class); @Test diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java index 38d8b318d0..4911c54671 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jms/artemis/ArtemisAutoConfigurationTests.java @@ -43,8 +43,8 @@ import org.junit.rules.TemporaryFolder; import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration; import org.springframework.boot.test.context.ContextLoader; +import org.springframework.boot.test.context.StandardContextLoader; import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jms.core.JmsTemplate; @@ -66,8 +66,7 @@ public class ArtemisAutoConfigurationTests { @Rule public final TemporaryFolder folder = new TemporaryFolder(); - private final ContextLoader contextLoader = ContextLoader - .standard() + private final StandardContextLoader contextLoader = ContextLoader.standard() .autoConfig(ArtemisAutoConfiguration.class, JmsAutoConfiguration.class); @Test diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/HttpHandlerAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/HttpHandlerAutoConfigurationTests.java index 5005060228..bc5f5c520e 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/HttpHandlerAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/HttpHandlerAutoConfigurationTests.java @@ -19,7 +19,7 @@ package org.springframework.boot.autoconfigure.web.reactive; import org.junit.Test; import org.springframework.boot.test.context.ContextLoader; -import org.springframework.boot.web.reactive.context.GenericReactiveWebApplicationContext; +import org.springframework.boot.test.context.ReactiveWebContextLoader; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.server.reactive.HttpHandler; @@ -39,8 +39,8 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class HttpHandlerAutoConfigurationTests { - private final ContextLoader contextLoader = ContextLoader - .reactiveWeb().autoConfig(HttpHandlerAutoConfiguration.class); + private final ReactiveWebContextLoader contextLoader = ContextLoader.reactiveWeb() + .autoConfig(HttpHandlerAutoConfiguration.class); @Test public void shouldNotProcessIfExistingHttpHandler() { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java index 248740bb71..66d71c4c45 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java @@ -38,6 +38,7 @@ import org.springframework.boot.autoconfigure.validation.ValidatorAdapter; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.WelcomePageHandlerMapping; import org.springframework.boot.test.context.ContextLoader; +import org.springframework.boot.test.context.ServletWebContextLoader; import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor; import org.springframework.boot.web.servlet.filter.OrderedHttpPutFormContentFilter; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; @@ -61,7 +62,6 @@ import org.springframework.validation.Validator; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.accept.ContentNegotiationManager; import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.filter.HttpPutFormContentFilter; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.HandlerExceptionResolver; @@ -114,8 +114,7 @@ public class WebMvcAutoConfigurationTests { private static final MockServletWebServerFactory webServerFactory = new MockServletWebServerFactory(); - private final ContextLoader contextLoader = ContextLoader - .servletWeb() + private final ServletWebContextLoader contextLoader = ContextLoader.servletWeb() .autoConfig(WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class) @@ -236,7 +235,6 @@ public class WebMvcAutoConfigurationTests { assertThat(resolver.getStrategyMap().get("/**/*.js")) .isInstanceOf(FixedVersionStrategy.class); }); - ; } @Test @@ -575,7 +573,7 @@ public class WebMvcAutoConfigurationTests { public void welcomePageMappingProducesNotFoundResponseWhenThereIsNoWelcomePage() { this.contextLoader .env("spring.resources.static-locations:classpath:/no-welcome-page/"); - this.contextLoader.load(context -> { + this.contextLoader.loadWeb(context -> { assertThat(context.getBeansOfType(WelcomePageHandlerMapping.class)) .hasSize(1); MockMvcBuilders.webAppContextSetup(context).build() @@ -600,7 +598,7 @@ public class WebMvcAutoConfigurationTests { public void welcomePageMappingHandlesRequestsThatAcceptTextHtml() { this.contextLoader .env("spring.resources.static-locations:classpath:/welcome-page/"); - this.contextLoader.load(context -> { + this.contextLoader.loadWeb(context -> { assertThat(context.getBeansOfType(WelcomePageHandlerMapping.class)) .hasSize(1); MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build(); @@ -615,7 +613,7 @@ public class WebMvcAutoConfigurationTests { public void welcomePageMappingDoesNotHandleRequestsThatDoNotAcceptTextHtml() { this.contextLoader .env("spring.resources.static-locations:classpath:/welcome-page/"); - this.contextLoader.load(context -> { + this.contextLoader.loadWeb(context -> { assertThat(context.getBeansOfType(WelcomePageHandlerMapping.class)) .hasSize(1); MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build(); @@ -628,7 +626,7 @@ public class WebMvcAutoConfigurationTests { public void welcomePageMappingHandlesRequestsWithNoAcceptHeader() { this.contextLoader .env("spring.resources.static-locations:classpath:/welcome-page/"); - this.contextLoader.load(context -> { + this.contextLoader.loadWeb(context -> { assertThat(context.getBeansOfType(WelcomePageHandlerMapping.class)) .hasSize(1); MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build(); @@ -642,7 +640,7 @@ public class WebMvcAutoConfigurationTests { throws Exception { this.contextLoader .env("spring.resources.static-locations:classpath:/welcome-page/"); - this.contextLoader.load(context -> { + this.contextLoader.loadWeb(context -> { assertThat(context.getBeansOfType(WelcomePageHandlerMapping.class)) .hasSize(1); MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build(); @@ -656,7 +654,7 @@ public class WebMvcAutoConfigurationTests { throws Exception { this.contextLoader .env("spring.resources.static-locations:classpath:/welcome-page"); - this.contextLoader.load(context -> { + this.contextLoader.loadWeb(context -> { assertThat(context.getBeansOfType(WelcomePageHandlerMapping.class)) .hasSize(1); MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build(); diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfigurationTests.java index 343c9f5a57..c1cd76bde8 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfigurationTests.java @@ -22,9 +22,9 @@ import org.junit.rules.ExpectedException; import org.springframework.beans.factory.BeanCreationException; import org.springframework.boot.test.context.ContextLoader; +import org.springframework.boot.test.context.ServletWebContextLoader; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import static org.assertj.core.api.Assertions.assertThat; @@ -37,8 +37,8 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class WebServicesAutoConfigurationTests { - private final ContextLoader contextLoader = ContextLoader - .servletWeb().autoConfig(WebServicesAutoConfiguration.class); + private final ServletWebContextLoader contextLoader = ContextLoader.servletWeb() + .autoConfig(WebServicesAutoConfiguration.class); @Rule public ExpectedException thrown = ExpectedException.none(); diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/TestDatabaseAutoConfigurationTests.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/TestDatabaseAutoConfigurationTests.java index 73f129794a..de899a08af 100644 --- a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/TestDatabaseAutoConfigurationTests.java +++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/jdbc/TestDatabaseAutoConfigurationTests.java @@ -21,7 +21,7 @@ import javax.sql.DataSource; import org.junit.Test; import org.springframework.boot.test.context.ContextLoader; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.boot.test.context.StandardContextLoader; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; @@ -38,8 +38,8 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class TestDatabaseAutoConfigurationTests { - private final ContextLoader contextLoader = ContextLoader - .standard().autoConfig(TestDatabaseAutoConfiguration.class); + private final StandardContextLoader contextLoader = ContextLoader.standard() + .autoConfig(TestDatabaseAutoConfiguration.class); @Test public void replaceWithNoDataSourceAvailable() { diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestDatabaseAutoConfigurationNoEmbeddedTests.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestDatabaseAutoConfigurationNoEmbeddedTests.java index 5f17c3d91d..2884d1d328 100644 --- a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestDatabaseAutoConfigurationNoEmbeddedTests.java +++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestDatabaseAutoConfigurationNoEmbeddedTests.java @@ -24,9 +24,9 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.BeanCreationException; import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration; import org.springframework.boot.test.context.ContextLoader; +import org.springframework.boot.test.context.StandardContextLoader; import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions; import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -44,8 +44,8 @@ import static org.mockito.Mockito.mock; @ClassPathExclusions({ "h2-*.jar", "hsqldb-*.jar", "derby-*.jar" }) public class TestDatabaseAutoConfigurationNoEmbeddedTests { - private final ContextLoader contextLoader = ContextLoader - .standard().config(ExistingDataSourceConfiguration.class) + private final StandardContextLoader contextLoader = ContextLoader.standard() + .config(ExistingDataSourceConfiguration.class) .autoConfig(TestDatabaseAutoConfiguration.class); @Test diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/AbstractContextLoader.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/AbstractContextLoader.java new file mode 100644 index 0000000000..7bf3fb03c8 --- /dev/null +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/AbstractContextLoader.java @@ -0,0 +1,321 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.test.context; + +import java.io.Closeable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigRegistry; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Base implementation of {@link ContextLoader}. + * + * @param the type of the context to be loaded + * @param the type of the loader + * @author Stephane Nicoll + * @author Andy Wilkinson + */ +class AbstractContextLoader> + implements ContextLoader { + + private final Map systemProperties = new HashMap<>(); + + private final List env = new ArrayList<>(); + + private final Set> userConfigurations = new LinkedHashSet<>(); + + private final LinkedList> autoConfigurations = new LinkedList<>(); + + private final Supplier contextSupplier; + + private ClassLoader classLoader; + + protected AbstractContextLoader(Supplier contextSupplier) { + this.contextSupplier = contextSupplier; + } + + /** + * Set the specified system property prior to loading the context and restore its + * previous value once the consumer has been invoked and the context closed. If the + * {@code value} is {@code null} this removes any prior customization for that key. + * @param key the system property + * @param value the value (can be null to remove any existing customization) + * @return this instance + */ + @Override + public L systemProperty(String key, String value) { + Assert.notNull(key, "Key must not be null"); + if (value != null) { + this.systemProperties.put(key, value); + } + else { + this.systemProperties.remove(key); + } + return self(); + } + + /** + * Add the specified property pairs. Key-value pairs can be specified with colon (":") + * or equals ("=") separators. Override matching keys that might have been specified + * previously. + * @param pairs the key-value pairs for properties that need to be added to the + * environment + * @return this instance + */ + @Override + public L env(String... pairs) { + if (!ObjectUtils.isEmpty(pairs)) { + this.env.addAll(Arrays.asList(pairs)); + } + return self(); + } + + /** + * Add the specified user configuration classes. + * @param configs the user configuration classes to add + * @return this instance + */ + @Override + public L config(Class... configs) { + if (!ObjectUtils.isEmpty(configs)) { + this.userConfigurations.addAll(Arrays.asList(configs)); + } + return self(); + } + + /** + * Add the specified auto-configuration classes. + * @param autoConfigurations the auto-configuration classes to add + * @return this instance + */ + @Override + public L autoConfig(Class... autoConfigurations) { + if (!ObjectUtils.isEmpty(autoConfigurations)) { + this.autoConfigurations.addAll(Arrays.asList(autoConfigurations)); + } + return self(); + } + + /** + * Add the specified auto-configurations at the beginning (in that order) so that it + * is applied before any other existing auto-configurations, but after any user + * configuration. If {@code A} and {@code B} are specified, {@code A} will be + * processed, then {@code B} and finally the rest of the existing auto-configuration. + * @param autoConfigurations the auto-configuration to add + * @return this instance + */ + @Override + public L autoConfigFirst(Class... autoConfigurations) { + this.autoConfigurations.addAll(0, Arrays.asList(autoConfigurations)); + return self(); + } + + /** + * Customize the {@link ClassLoader} that the {@link ApplicationContext} should use. + * Customizing the {@link ClassLoader} is an effective manner to hide resources from + * the classpath. + * @param classLoader the classloader to use (can be null to use the default) + * @return this instance + * @see HidePackagesClassLoader + */ + @Override + public L classLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + return self(); + } + + protected final L self() { + return (L) this; + } + + + /** + * Create and refresh a new {@link ApplicationContext} based on the current state of + * this loader. The context is consumed by the specified {@link ContextConsumer} and + * closed upon completion. + * @param consumer the consumer of the created {@link ApplicationContext} + */ + @Override + public void load(ContextConsumer consumer) { + doLoad(consumer::accept); + } + + protected void doLoad(ContextHandler contextHandler) { + try (ApplicationContextLifecycleHandler handler = new ApplicationContextLifecycleHandler()) { + try { + T ctx = handler.load(); + contextHandler.handle(ctx); + } + catch (RuntimeException ex) { + throw ex; + } + catch (Throwable ex) { + throw new IllegalStateException( + "An unexpected error occurred: " + ex.getMessage(), ex); + } + } + } + + /** + * Create and refresh a new {@link ApplicationContext} based on the current state of + * this loader that this expected to fail. If the context does not fail, an + * {@link AssertionError} is thrown. Otherwise the exception is consumed by the + * specified {@link Consumer} with no expectation on the type of the exception. + * @param consumer the consumer of the failure + */ + @Override + public void loadAndFail(Consumer consumer) { + loadAndFail(Throwable.class, consumer); + } + + /** + * Create and refresh a new {@link ApplicationContext} based on the current state of + * this loader that this expected to fail. If the context does not fail, an + * {@link AssertionError} is thrown. If the exception does not match the specified + * {@code exceptionType}, an {@link AssertionError} is thrown as well. If the + * exception type matches, it is consumed by the specified {@link Consumer}. + * @param exceptionType the expected type of the failure + * @param consumer the consumer of the failure + * @param the expected type of the failure + */ + @Override + public void loadAndFail(Class exceptionType, + Consumer consumer) { + try (ApplicationContextLifecycleHandler handler = new ApplicationContextLifecycleHandler()) { + handler.load(); + throw new AssertionError("ApplicationContext should have failed"); + } + catch (Throwable ex) { + assertThat(ex).as("Wrong application context failure exception") + .isInstanceOf(exceptionType); + consumer.accept(exceptionType.cast(ex)); + } + } + + private T configureApplicationContext() { + T context = AbstractContextLoader.this.contextSupplier.get(); + if (this.classLoader != null) { + if (context instanceof DefaultResourceLoader) { + ((DefaultResourceLoader) context).setClassLoader(this.classLoader); + } + else { + throw new IllegalStateException("Cannot configure ClassLoader: " + context + + " is not a DefaultResourceLoader sub-class"); + } + } + if (!ObjectUtils.isEmpty(this.env)) { + TestPropertyValues.of(this.env.toArray(new String[this.env.size()])) + .applyTo(context); + } + if (!ObjectUtils.isEmpty(this.userConfigurations)) { + ((AnnotationConfigRegistry) context).register(this.userConfigurations + .toArray(new Class[this.userConfigurations.size()])); + } + if (!ObjectUtils.isEmpty(this.autoConfigurations)) { + LinkedHashSet> linkedHashSet = new LinkedHashSet<>( + this.autoConfigurations); + ((AnnotationConfigRegistry) context).register( + linkedHashSet.toArray(new Class[this.autoConfigurations.size()])); + } + return context; + } + + /** + * An internal callback interface that handles a concrete {@link ApplicationContext} + * type. + * @param the type of the application context + */ + protected interface ContextHandler { + + void handle(T context) throws Throwable; + + } + + /** + * Handles the lifecycle of the {@link ApplicationContext}. + */ + private class ApplicationContextLifecycleHandler implements Closeable { + + private final Map customSystemProperties; + + private final Map previousSystemProperties = new HashMap<>(); + + private ConfigurableApplicationContext context; + + ApplicationContextLifecycleHandler() { + this.customSystemProperties = new HashMap<>( + AbstractContextLoader.this.systemProperties); + } + + public T load() { + setCustomSystemProperties(); + T context = configureApplicationContext(); + context.refresh(); + this.context = context; + return context; + } + + @Override + public void close() { + try { + if (this.context != null) { + this.context.close(); + } + } + finally { + unsetCustomSystemProperties(); + } + } + + private void setCustomSystemProperties() { + this.customSystemProperties.forEach((key, value) -> { + String previous = System.setProperty(key, value); + this.previousSystemProperties.put(key, previous); + }); + } + + private void unsetCustomSystemProperties() { + this.previousSystemProperties.forEach((key, value) -> { + if (value != null) { + System.setProperty(key, value); + } + else { + System.clearProperty(key); + } + }); + } + + } + +} diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/ContextConsumer.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/ContextConsumer.java index 82d4af4309..aa6fb8fb77 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/context/ContextConsumer.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/ContextConsumer.java @@ -25,16 +25,15 @@ import org.springframework.context.ConfigurableApplicationContext; * @author Stephane Nicoll * @author Andy Wilkinson * @since 2.0.0 - * @param the type of the context that can be consumed */ @FunctionalInterface -public interface ContextConsumer { +public interface ContextConsumer { /** * Performs this operation on the supplied {@code context}. * @param context the application context to consume * @throws Throwable any exception that might occur in assertions */ - void accept(T context) throws Throwable; + void accept(ConfigurableApplicationContext context) throws Throwable; } diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/ContextLoader.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/ContextLoader.java index baa5be801a..4b3aae0601 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/context/ContextLoader.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/ContextLoader.java @@ -20,7 +20,6 @@ import java.util.function.Consumer; import org.springframework.boot.web.reactive.context.GenericReactiveWebApplicationContext; import org.springframework.context.ApplicationContext; -import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.mock.web.MockServletContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; @@ -32,7 +31,7 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon *
  * public class FooAutoConfigurationTests {
  *
- *     private final ContextLoader contextLoader = new ContextLoader()
+ *     private final ContextLoader contextLoader = ContextLoader.standard()
  *             .autoConfig(FooAutoConfiguration.class).env("spring.foo=bar");
  *
  * }
@@ -67,6 +66,10 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon * automatically closed. * *

+ * Web environment can easily be simulated using the {@link #servletWeb()} and + * {@link #reactiveWeb()} factory methods. + * + *

* If a failure scenario has to be tested, {@link #loadAndFail(Consumer)} can be used * instead: it expects the startup of the context to fail and call the {@link Consumer} * with the exception for further assertions. @@ -74,9 +77,8 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon * @author Stephane Nicoll * @author Andy Wilkinson * @since 2.0.0 - * @param the type of the context to be loaded */ -public interface ContextLoader { +public interface ContextLoader { /** * Creates a {@code ContextLoader} that will load a standard @@ -84,9 +86,8 @@ public interface ContextLoader { * * @return the context loader */ - static ContextLoader standard() { - return new StandardContextLoader<>( - () -> new AnnotationConfigApplicationContext()); + static StandardContextLoader standard() { + return new StandardContextLoader(AnnotationConfigApplicationContext::new); } /** @@ -95,8 +96,8 @@ public interface ContextLoader { * * @return the context loader */ - static ContextLoader servletWeb() { - return new StandardContextLoader<>(() -> { + static ServletWebContextLoader servletWeb() { + return new ServletWebContextLoader(() -> { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.setServletContext(new MockServletContext()); return context; @@ -109,9 +110,8 @@ public interface ContextLoader { * * @return the context loader */ - static ContextLoader reactiveWeb() { - return new StandardContextLoader<>( - () -> new GenericReactiveWebApplicationContext()); + static ReactiveWebContextLoader reactiveWeb() { + return new ReactiveWebContextLoader(GenericReactiveWebApplicationContext::new); } /** @@ -122,7 +122,7 @@ public interface ContextLoader { * @param value the value (can be null to remove any existing customization) * @return this instance */ - public ContextLoader systemProperty(String key, String value); + ContextLoader systemProperty(String key, String value); /** * Add the specified property pairs. Key-value pairs can be specified with colon (":") @@ -132,21 +132,21 @@ public interface ContextLoader { * environment * @return this instance */ - public ContextLoader env(String... pairs); + ContextLoader env(String... pairs); /** * Add the specified user configuration classes. * @param configs the user configuration classes to add * @return this instance */ - public ContextLoader config(Class... configs); + ContextLoader config(Class... configs); /** * Add the specified auto-configuration classes. * @param autoConfigurations the auto-configuration classes to add * @return this instance */ - public ContextLoader autoConfig(Class... autoConfigurations); + ContextLoader autoConfig(Class... autoConfigurations); /** * Add the specified auto-configurations at the beginning (in that order) so that it @@ -156,7 +156,7 @@ public interface ContextLoader { * @param autoConfigurations the auto-configuration to add * @return this instance */ - public ContextLoader autoConfigFirst(Class... autoConfigurations); + ContextLoader autoConfigFirst(Class... autoConfigurations); /** * Customize the {@link ClassLoader} that the {@link ApplicationContext} should use. @@ -166,15 +166,15 @@ public interface ContextLoader { * @return this instance * @see HidePackagesClassLoader */ - public ContextLoader classLoader(ClassLoader classLoader); + ContextLoader classLoader(ClassLoader classLoader); /** * Create and refresh a new {@link ApplicationContext} based on the current state of - * this loader. The context is consumed by the specified {@code consumers} and closed + * this loader. The context is consumed by the specified {@code consumer} and closed * upon completion. * @param consumer the consumer of the created {@link ApplicationContext} */ - public void load(ContextConsumer consumer); + void load(ContextConsumer consumer); /** * Create and refresh a new {@link ApplicationContext} based on the current state of @@ -183,7 +183,7 @@ public interface ContextLoader { * specified {@link Consumer} with no expectation on the type of the exception. * @param consumer the consumer of the failure */ - public void loadAndFail(Consumer consumer); + void loadAndFail(Consumer consumer); /** * Create and refresh a new {@link ApplicationContext} based on the current state of @@ -195,7 +195,6 @@ public interface ContextLoader { * @param consumer the consumer of the failure * @param the expected type of the failure */ - public void loadAndFail(Class exceptionType, - Consumer consumer); + void loadAndFail(Class exceptionType, Consumer consumer); } diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/ReactiveWebContextLoader.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/ReactiveWebContextLoader.java new file mode 100644 index 0000000000..015fcb9282 --- /dev/null +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/ReactiveWebContextLoader.java @@ -0,0 +1,39 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.test.context; + +import java.util.function.Supplier; + +import org.springframework.boot.web.reactive.context.GenericReactiveWebApplicationContext; + +/** + * A {@link ContextLoader} that simulates a {@link GenericReactiveWebApplicationContext} + * which can be useful to test components that require a reactive web application. + * + * @author Andy Wilkinson + * @author Stephane Nicoll + * @since 2.0.0 + */ +public final class ReactiveWebContextLoader + extends AbstractContextLoader { + + ReactiveWebContextLoader( + Supplier contextSupplier) { + super(contextSupplier); + } + +} diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/ServletWebContextLoader.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/ServletWebContextLoader.java new file mode 100644 index 0000000000..b609d113f8 --- /dev/null +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/ServletWebContextLoader.java @@ -0,0 +1,50 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.test.context; + +import java.util.function.Supplier; + +import org.springframework.web.context.ConfigurableWebApplicationContext; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; + +/** + * A {@link ContextLoader} that simulates a {@link AnnotationConfigWebApplicationContext} + * which can be useful to test components that require a servlet web application. + * + * @author Andy Wilkinson + * @author Stephane Nicoll + * @since 2.0.0 + */ +public final class ServletWebContextLoader + extends AbstractContextLoader { + + ServletWebContextLoader( + Supplier contextSupplier) { + super(contextSupplier); + } + + /** + * Create and refresh a new {@link ConfigurableWebApplicationContext} based on the + * current state of this loader. The context is consumed by the specified + * {@link WebMvcContextConsumer consumer} and closed upon completion. + * @param consumer the consumer of the created {@link ConfigurableWebApplicationContext} + */ + public void loadWeb(WebMvcContextConsumer consumer) { + doLoad(consumer::accept); + } + +} diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/StandardContextLoader.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/StandardContextLoader.java index e15c560893..5c2749bff0 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/context/StandardContextLoader.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/StandardContextLoader.java @@ -16,285 +16,22 @@ package org.springframework.boot.test.context; -import java.io.Closeable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Consumer; import java.util.function.Supplier; -import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.AnnotationConfigRegistry; -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; - -import static org.assertj.core.api.Assertions.assertThat; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** - * Standard implementation of {@link ContextLoader}. + * A {@link ContextLoader} that simulates a standard, non web environment. * * @author Stephane Nicoll * @author Andy Wilkinson - * @param the type of the context to be loaded + * @since 2.0.0 */ -final class StandardContextLoader - implements ContextLoader { - - private final Map systemProperties = new HashMap<>(); - - private final List env = new ArrayList<>(); - - private final Set> userConfigurations = new LinkedHashSet<>(); - - private final LinkedList> autoConfigurations = new LinkedList<>(); - - private final Supplier contextSupplier; - - private ClassLoader classLoader; - - StandardContextLoader(Supplier contextSupplier) { - this.contextSupplier = contextSupplier; - } - - /** - * Set the specified system property prior to loading the context and restore its - * previous value once the consumer has been invoked and the context closed. If the - * {@code value} is {@code null} this removes any prior customization for that key. - * @param key the system property - * @param value the value (can be null to remove any existing customization) - * @return this instance - */ - @Override - public StandardContextLoader systemProperty(String key, String value) { - Assert.notNull(key, "Key must not be null"); - if (value != null) { - this.systemProperties.put(key, value); - } - else { - this.systemProperties.remove(key); - } - return this; - } - - /** - * Add the specified property pairs. Key-value pairs can be specified with colon (":") - * or equals ("=") separators. Override matching keys that might have been specified - * previously. - * @param pairs the key-value pairs for properties that need to be added to the - * environment - * @return this instance - */ - @Override - public StandardContextLoader env(String... pairs) { - if (!ObjectUtils.isEmpty(pairs)) { - this.env.addAll(Arrays.asList(pairs)); - } - return this; - } - - /** - * Add the specified user configuration classes. - * @param configs the user configuration classes to add - * @return this instance - */ - @Override - public StandardContextLoader config(Class... configs) { - if (!ObjectUtils.isEmpty(configs)) { - this.userConfigurations.addAll(Arrays.asList(configs)); - } - return this; - } - - /** - * Add the specified auto-configuration classes. - * @param autoConfigurations the auto-configuration classes to add - * @return this instance - */ - @Override - public StandardContextLoader autoConfig(Class... autoConfigurations) { - if (!ObjectUtils.isEmpty(autoConfigurations)) { - this.autoConfigurations.addAll(Arrays.asList(autoConfigurations)); - } - return this; - } - - /** - * Add the specified auto-configurations at the beginning (in that order) so that it - * is applied before any other existing auto-configurations, but after any user - * configuration. If {@code A} and {@code B} are specified, {@code A} will be - * processed, then {@code B} and finally the rest of the existing auto-configuration. - * @param autoConfigurations the auto-configuration to add - * @return this instance - */ - @Override - public StandardContextLoader autoConfigFirst(Class... autoConfigurations) { - this.autoConfigurations.addAll(0, Arrays.asList(autoConfigurations)); - return this; - } - - /** - * Customize the {@link ClassLoader} that the {@link ApplicationContext} should use. - * Customizing the {@link ClassLoader} is an effective manner to hide resources from - * the classpath. - * @param classLoader the classloader to use (can be null to use the default) - * @return this instance - * @see HidePackagesClassLoader - */ - @Override - public StandardContextLoader classLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - return this; - } - - /** - * Create and refresh a new {@link ApplicationContext} based on the current state of - * this loader. The context is consumed by the specified {@link ContextConsumer} and - * closed upon completion. - * @param consumer the consumer of the created {@link ApplicationContext} - */ - @Override - public void load(ContextConsumer consumer) { - try (ApplicationContextLifecycleHandler handler = new ApplicationContextLifecycleHandler()) { - try { - T ctx = handler.load(); - consumer.accept(ctx); - } - catch (RuntimeException ex) { - throw ex; - } - catch (Throwable ex) { - throw new IllegalStateException( - "An unexpected error occurred: " + ex.getMessage(), ex); - } - } - } - - /** - * Create and refresh a new {@link ApplicationContext} based on the current state of - * this loader that this expected to fail. If the context does not fail, an - * {@link AssertionError} is thrown. Otherwise the exception is consumed by the - * specified {@link Consumer} with no expectation on the type of the exception. - * @param consumer the consumer of the failure - */ - @Override - public void loadAndFail(Consumer consumer) { - loadAndFail(Throwable.class, consumer); - } - - /** - * Create and refresh a new {@link ApplicationContext} based on the current state of - * this loader that this expected to fail. If the context does not fail, an - * {@link AssertionError} is thrown. If the exception does not match the specified - * {@code exceptionType}, an {@link AssertionError} is thrown as well. If the - * exception type matches, it is consumed by the specified {@link Consumer}. - * @param exceptionType the expected type of the failure - * @param consumer the consumer of the failure - * @param the expected type of the failure - */ - @Override - public void loadAndFail(Class exceptionType, - Consumer consumer) { - try (ApplicationContextLifecycleHandler handler = new ApplicationContextLifecycleHandler()) { - handler.load(); - throw new AssertionError("ApplicationContext should have failed"); - } - catch (Throwable ex) { - assertThat(ex).as("Wrong application context failure exception") - .isInstanceOf(exceptionType); - consumer.accept(exceptionType.cast(ex)); - } - } - - private T configureApplicationContext() { - T context = StandardContextLoader.this.contextSupplier.get(); - if (this.classLoader != null) { - if (context instanceof DefaultResourceLoader) { - ((DefaultResourceLoader) context).setClassLoader(this.classLoader); - } - else { - throw new IllegalStateException("Cannot configure ClassLoader: " + context - + " is not a DefaultResourceLoader sub-class"); - } - } - if (!ObjectUtils.isEmpty(this.env)) { - TestPropertyValues.of(this.env.toArray(new String[this.env.size()])) - .applyTo(context); - } - if (!ObjectUtils.isEmpty(this.userConfigurations)) { - context.register(this.userConfigurations - .toArray(new Class[this.userConfigurations.size()])); - } - if (!ObjectUtils.isEmpty(this.autoConfigurations)) { - LinkedHashSet> linkedHashSet = new LinkedHashSet<>( - this.autoConfigurations); - context.register( - linkedHashSet.toArray(new Class[this.autoConfigurations.size()])); - } - return context; - } - - /** - * Handles the lifecycle of the {@link ApplicationContext}. - */ - private class ApplicationContextLifecycleHandler implements Closeable { - - private final Map customSystemProperties; - - private final Map previousSystemProperties = new HashMap<>(); - - private ConfigurableApplicationContext context; - - ApplicationContextLifecycleHandler() { - this.customSystemProperties = new HashMap<>( - StandardContextLoader.this.systemProperties); - } - - public T load() { - setCustomSystemProperties(); - T context = configureApplicationContext(); - context.refresh(); - this.context = context; - return context; - } - - @Override - public void close() { - try { - if (this.context != null) { - this.context.close(); - } - } - finally { - unsetCustomSystemProperties(); - } - } - - private void setCustomSystemProperties() { - this.customSystemProperties.forEach((key, value) -> { - String previous = System.setProperty(key, value); - this.previousSystemProperties.put(key, previous); - }); - } - - private void unsetCustomSystemProperties() { - this.previousSystemProperties.forEach((key, value) -> { - if (value != null) { - System.setProperty(key, value); - } - else { - System.clearProperty(key); - } - }); - } +public class StandardContextLoader + extends AbstractContextLoader { + public StandardContextLoader(Supplier contextSupplier) { + super(contextSupplier); } } diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/WebMvcContextConsumer.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/WebMvcContextConsumer.java new file mode 100644 index 0000000000..b982a0533d --- /dev/null +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/WebMvcContextConsumer.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.test.context; + +import org.springframework.web.context.ConfigurableWebApplicationContext; + +/** + * Specialized callback interface used in tests to process a running + * {@link ConfigurableWebApplicationContext} with the ability to throw a (checked) + * exception. + * + * @author Stephane Nicoll + * @see ContextConsumer + * @since 2.0.0 + */ +@FunctionalInterface +public interface WebMvcContextConsumer { + + /** + * Performs this operation on the supplied {@code context}. + * @param context the application context to consume + * @throws Throwable any exception that might occur in assertions + */ + void accept(ConfigurableWebApplicationContext context) throws Throwable; + +} diff --git a/spring-boot-test/src/test/java/org/springframework/boot/test/context/StandardContextLoaderTests.java b/spring-boot-test/src/test/java/org/springframework/boot/test/context/StandardContextLoaderTests.java index 7208cc434d..4e9aafad3e 100644 --- a/spring-boot-test/src/test/java/org/springframework/boot/test/context/StandardContextLoaderTests.java +++ b/spring-boot-test/src/test/java/org/springframework/boot/test/context/StandardContextLoaderTests.java @@ -28,14 +28,13 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.test.context.support.AbstractContextLoader; import org.springframework.util.ClassUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; /** - * Tests for {@link AbstractContextLoader}. + * Tests for {@link StandardContextLoader}. * * @author Stephane Nicoll */ @@ -44,8 +43,8 @@ public class StandardContextLoaderTests { @Rule public final ExpectedException thrown = ExpectedException.none(); - private final StandardContextLoader contextLoader = new StandardContextLoader<>( - () -> new AnnotationConfigApplicationContext()); + private final StandardContextLoader contextLoader = new StandardContextLoader( + AnnotationConfigApplicationContext::new); @Test public void systemPropertyIsSetAndRemoved() {