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 f611737258..761a39f52a 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 @@ -337,16 +337,32 @@ public abstract class AbstractApplicationContextRunner consumer) { - withContextClassLoader(this.runnerConfiguration.classLoader, - () -> this.runnerConfiguration.systemProperties.applyToSystemProperties(() -> { - try (A context = createAssertableContext()) { - accept(consumer, context); - } - return null; - })); + withContextClassLoader(this.runnerConfiguration.classLoader, () -> this.runnerConfiguration.systemProperties + .applyToSystemProperties(() -> consumeAssertableContext(true, consumer))); return (SELF) this; } + /** + * Prepare a new {@link ApplicationContext} based on the current state of this loader. + * The context is consumed by the specified {@code consumer} and closed upon + * completion. Unlike {@link #run(ContextConsumer)}, this method does not refresh the + * consumed context. + * @param consumer the consumer of the created {@link ApplicationContext} + * @return this instance + */ + @SuppressWarnings("unchecked") + public SELF prepare(ContextConsumer consumer) { + withContextClassLoader(this.runnerConfiguration.classLoader, () -> this.runnerConfiguration.systemProperties + .applyToSystemProperties(() -> consumeAssertableContext(false, consumer))); + return (SELF) this; + } + + private void consumeAssertableContext(boolean refresh, ContextConsumer consumer) { + try (A context = createAssertableContext(refresh)) { + accept(consumer, context); + } + } + private void withContextClassLoader(ClassLoader classLoader, Runnable action) { if (classLoader == null) { action.run(); @@ -365,14 +381,14 @@ public abstract class AbstractApplicationContextRunner assertType = (Class) resolvableType.resolveGeneric(1); Class contextType = (Class) resolvableType.resolveGeneric(2); - return ApplicationContextAssertProvider.get(assertType, contextType, this::createAndLoadContext); + return ApplicationContextAssertProvider.get(assertType, contextType, () -> createAndLoadContext(refresh)); } - private C createAndLoadContext() { + private C createAndLoadContext(boolean refresh) { C context = this.runnerConfiguration.contextFactory.get(); ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); if (beanFactory instanceof AbstractAutowireCapableBeanFactory) { @@ -384,7 +400,7 @@ public abstract class AbstractApplicationContextRunner 0) { ((AnnotationConfigRegistry) context).register(classes); } - context.refresh(); + if (refresh) { + context.refresh(); + } } private void accept(ContextConsumer consumer, A context) { 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 6b694a74b4..8c5321db9f 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 @@ -47,6 +47,7 @@ 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.assertThatIllegalStateException; /** * Abstract tests for {@link AbstractApplicationContextRunner} implementations. @@ -238,6 +239,16 @@ abstract class AbstractApplicationContextRunnerTests assertThat(context).hasSingleBean(ProfileConfig.class)); } + @Test + void prepareDoesNotRefreshContext() { + get().withUserConfiguration(FooConfig.class).prepare((context) -> { + assertThatIllegalStateException().isThrownBy(() -> context.getBean(String.class)) + .withMessageContaining("not been refreshed"); + context.getSourceApplicationContext().refresh(); + assertThat(context.getBean(String.class)).isEqualTo("foo"); + }); + } + protected abstract T get(); private static void throwCheckedException(String message) throws IOException {