diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/flyway/FlywayEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/flyway/FlywayEndpointTests.java index df97d7e1d9..97486d7260 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/flyway/FlywayEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/flyway/FlywayEndpointTests.java @@ -41,7 +41,7 @@ public class FlywayEndpointTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class)) .withUserConfiguration(EmbeddedDataSourceConfiguration.class) - .withBean("endpoint", FlywayEndpoint.class, FlywayEndpoint::new); + .withBean("endpoint", FlywayEndpoint.class); @Test public void flywayReportIsProduced() { diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java index 5350a00731..6b26d3cf7e 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java @@ -19,9 +19,12 @@ package org.springframework.boot.test.context.runner; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionCustomizer; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.boot.context.annotation.Configurations; import org.springframework.boot.context.annotation.UserConfigurations; @@ -112,6 +115,8 @@ public abstract class AbstractApplicationContextRunner> beanRegistrations; + private final List configurations; /** @@ -120,7 +125,8 @@ public abstract class AbstractApplicationContextRunner contextFactory) { this(contextFactory, Collections.emptyList(), TestPropertyValues.empty(), - TestPropertyValues.empty(), null, null, Collections.emptyList()); + TestPropertyValues.empty(), null, null, Collections.emptyList(), + Collections.emptyList()); } /** @@ -131,12 +137,14 @@ public abstract class AbstractApplicationContextRunner contextFactory, List> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, + List> beanRegistrations, List configurations) { Assert.notNull(contextFactory, "ContextFactory must not be null"); Assert.notNull(environmentProperties, "EnvironmentProperties must not be null"); @@ -149,6 +157,7 @@ public abstract class AbstractApplicationContextRunner * Such beans are registered after regular {@linkplain #withUserConfiguration(Class[]) * user configurations} in the order of registration. - * @param beanType the type of the bean - * @param beanDefinition a supplier for the bean + * @param type the type of the bean + * @param constructorArgs custom argument values to be fed into Spring's constructor + * resolution algorithm, resolving either all arguments or just specific ones, with + * the rest to be resolved through regular autowiring (may be {@code null} or empty) * @param the type of the bean * @return a new instance with the updated bean */ - public SELF withBean(Class beanType, Supplier beanDefinition) { - return withBean(null, beanType, beanDefinition); + public SELF withBean(Class type, Object... constructorArgs) { + return withBean(null, type, constructorArgs); } /** - * Register the specified user bean with the {@link ApplicationContext}. The bean name - * is generated from the configured {@link BeanNameGenerator} on the underlying - * context. + * Register the specified user bean with the {@link ApplicationContext}. *

* Such beans are registered after regular {@linkplain #withUserConfiguration(Class[]) * user configurations} in the order of registration. - * @param beanType the type of the bean - * @param beanDefinition a function that accepts the context and return the bean + * @param name the bean name or {@code null} to use a generated name + * @param type the type of the bean + * @param constructorArgs custom argument values to be fed into Spring's constructor + * resolution algorithm, resolving either all arguments or just specific ones, with + * the rest to be resolved through regular autowiring (may be {@code null} or empty) * @param the type of the bean * @return a new instance with the updated bean */ - public SELF withBean(Class beanType, Function beanDefinition) { - return withBean(null, beanType, beanDefinition); + public SELF withBean(String name, Class type, Object... constructorArgs) { + return newInstance(this.contextFactory, this.initializers, + this.environmentProperties, this.systemProperties, this.classLoader, + this.parent, + add(this.beanRegistrations, + new BeanRegistration<>(name, type, constructorArgs)), + this.configurations); } /** - * Register the specified user bean with the {@link ApplicationContext}. If no bean - * name is provided, a default one is generated from the configured - * {@link BeanNameGenerator} on the underlying context. + * Register the specified user bean with the {@link ApplicationContext}. The bean name + * is generated from the configured {@link BeanNameGenerator} on the underlying + * context. *

* Such beans are registered after regular {@linkplain #withUserConfiguration(Class[]) * user configurations} in the order of registration. - * @param beanName the name of the bean (may be {@code null}) - * @param beanType the type of the bean - * @param beanDefinition a supplier for the bean + * @param type the type of the bean + * @param supplier a supplier for the bean + * @param customizers one or more callbacks for customizing the factory's + * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag * @param the type of the bean * @return a new instance with the updated bean */ - public SELF withBean(String beanName, Class beanType, - Supplier beanDefinition) { - return withBean(beanName, beanType, (context) -> beanDefinition.get()); + public SELF withBean(Class type, Supplier supplier, + BeanDefinitionCustomizer... customizers) { + return withBean(null, type, supplier, customizers); } /** - * Register the specified user bean with the {@link ApplicationContext}. If no bean - * name is provided, a default one is generated from the configured - * {@link BeanNameGenerator} on the underlying context. + * Register the specified user bean with the {@link ApplicationContext}. The bean name + * is generated from the configured {@link BeanNameGenerator} on the underlying + * context. *

* Such beans are registered after regular {@linkplain #withUserConfiguration(Class[]) * user configurations} in the order of registration. - * @param beanName the name of the bean (may be {@code null}) - * @param beanType the type of the bean - * @param beanDefinition a function that accepts the context and return the bean + * @param name the bean name or {@code null} to use a generated name + * @param type the type of the bean + * @param supplier a supplier for the bean + * @param customizers one or more callbacks for customizing the factory's + * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag * @param the type of the bean * @return a new instance with the updated bean */ - public SELF withBean(String beanName, Class beanType, - Function beanDefinition) { - return withInitializer( - beanDefinitionRegistrar(beanName, beanType, beanDefinition)); - } - - private ApplicationContextInitializer beanDefinitionRegistrar( - String beanName, Class beanType, Function beanDefinition) { - return (context) -> { - Assert.isInstanceOf(GenericApplicationContext.class, context); - ((GenericApplicationContext) context).registerBean(beanName, beanType, - () -> beanDefinition.apply(context)); - }; + public SELF withBean(String name, Class type, Supplier supplier, + BeanDefinitionCustomizer... customizers) { + return newInstance(this.contextFactory, this.initializers, + this.environmentProperties, this.systemProperties, this.classLoader, + this.parent, + add(this.beanRegistrations, + new BeanRegistration<>(name, type, supplier, customizers)), + this.configurations); } /** @@ -319,7 +336,8 @@ public abstract class AbstractApplicationContextRunner> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, + List> beanRegistrations, List configurations); /** @@ -416,6 +435,7 @@ public abstract class AbstractApplicationContextRunner 0) { ((AnnotationConfigRegistry) context).register(classes); } + this.beanRegistrations.forEach((registration) -> registration.apply(context)); this.initializers.forEach((initializer) -> initializer.initialize(context)); context.refresh(); } @@ -434,4 +454,31 @@ public abstract class AbstractApplicationContextRunner the bean type + */ + protected final class BeanRegistration { + + Consumer registrar; + + public BeanRegistration(String name, Class type, Object... constructorArgs) { + this.registrar = (context) -> context.registerBean(name, type, + constructorArgs); + } + + public BeanRegistration(String name, Class type, Supplier supplier, + BeanDefinitionCustomizer... customizers) { + this.registrar = (context) -> context.registerBean(name, type, supplier, + customizers); + } + + public void apply(ConfigurableApplicationContext context) { + Assert.isInstanceOf(GenericApplicationContext.class, context); + this.registrar.accept(((GenericApplicationContext) context)); + } + + } + } diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ApplicationContextRunner.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ApplicationContextRunner.java index 7165e82886..ffb9ae9310 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ApplicationContextRunner.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ApplicationContextRunner.java @@ -64,9 +64,10 @@ public class ApplicationContextRunner extends List> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, + List> beanRegistrations, List configurations) { super(contextFactory, initializers, environmentProperties, systemProperties, - classLoader, parent, configurations); + classLoader, parent, beanRegistrations, configurations); } @Override @@ -75,10 +76,11 @@ public class ApplicationContextRunner extends List> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, + List> beanRegistrations, List configurations) { return new ApplicationContextRunner(contextFactory, initializers, environmentProperties, systemProperties, classLoader, parent, - configurations); + beanRegistrations, configurations); } } diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunner.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunner.java index 19a367cf1a..87bcd7f8d6 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunner.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunner.java @@ -64,9 +64,10 @@ public final class ReactiveWebApplicationContextRunner extends List> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, + List> beanRegistrations, List configurations) { super(contextFactory, initializers, environmentProperties, systemProperties, - classLoader, parent, configurations); + classLoader, parent, beanRegistrations, configurations); } @Override @@ -75,10 +76,11 @@ public final class ReactiveWebApplicationContextRunner extends List> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, + List> beanRegistrations, List configurations) { return new ReactiveWebApplicationContextRunner(contextFactory, initializers, environmentProperties, systemProperties, classLoader, parent, - configurations); + beanRegistrations, configurations); } } diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/WebApplicationContextRunner.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/WebApplicationContextRunner.java index 072356f141..5b4387928e 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/WebApplicationContextRunner.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/WebApplicationContextRunner.java @@ -68,9 +68,10 @@ public final class WebApplicationContextRunner extends List> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, + List> beanRegistrations, List configurations) { super(contextFactory, initializers, environmentProperties, systemProperties, - classLoader, parent, configurations); + classLoader, parent, beanRegistrations, configurations); } @Override @@ -79,10 +80,11 @@ public final class WebApplicationContextRunner extends List> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, + List> beanRegistrations, List configurations) { return new WebApplicationContextRunner(contextFactory, initializers, environmentProperties, systemProperties, classLoader, parent, - configurations); + beanRegistrations, configurations); } /** diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunnerTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunnerTests.java index 520f95f970..4a83cd3b46 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunnerTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunnerTests.java @@ -39,7 +39,6 @@ import org.springframework.util.ClassUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIOException; -import static org.assertj.core.api.Assertions.entry; /** * Abstract tests for {@link AbstractApplicationContextRunner} implementations. @@ -167,15 +166,6 @@ public abstract class AbstractApplicationContextRunnerTests "Result: " + context.getBean("foo")) - .run((context) -> assertThat(context.getBeansOfType(String.class)) - .containsOnly(entry("foo", "foo"), - entry("string", "Result: foo"))); - } - @Test public void runWithMultipleConfigurationsShouldRegisterAllConfigurations() { get().withUserConfiguration(FooConfig.class)