Allow ApplicationContextRunner to return non-refreshed context

Add `AbstractApplicationContextRunner.prepare` which can be used to
test an `ApplicationContext` that has been prepared but not refreshed.

Closes gh-31302
pull/31304/head
Phillip Webb 2 years ago
parent 46c262d3cc
commit 11184aae8d

@ -337,16 +337,32 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
*/
@SuppressWarnings("unchecked")
public SELF run(ContextConsumer<? super A> 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<? super A> consumer) {
withContextClassLoader(this.runnerConfiguration.classLoader, () -> this.runnerConfiguration.systemProperties
.applyToSystemProperties(() -> consumeAssertableContext(false, consumer)));
return (SELF) this;
}
private void consumeAssertableContext(boolean refresh, ContextConsumer<? super A> 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<SELF extends AbstractAppl
}
@SuppressWarnings("unchecked")
private A createAssertableContext() {
private A createAssertableContext(boolean refresh) {
ResolvableType resolvableType = ResolvableType.forClass(AbstractApplicationContextRunner.class, getClass());
Class<A> assertType = (Class<A>) resolvableType.resolveGeneric(1);
Class<C> contextType = (Class<C>) 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<SELF extends AbstractAppl
}
}
try {
configureContext(context);
configureContext(context, refresh);
return context;
}
catch (RuntimeException ex) {
@ -393,7 +409,7 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
}
}
private void configureContext(C context) {
private void configureContext(C context, boolean refresh) {
if (this.runnerConfiguration.parent != null) {
context.setParent(this.runnerConfiguration.parent);
}
@ -408,7 +424,9 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
if (classes.length > 0) {
((AnnotationConfigRegistry) context).register(classes);
}
context.refresh();
if (refresh) {
context.refresh();
}
}
private void accept(ContextConsumer<? super A> consumer, A context) {

@ -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<T extends AbstractApplicati
.run((context) -> 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 {

Loading…
Cancel
Save