Rich AssertJ-based assertions for validating application contexts, beans, and context startup failures.
org.springframework.boot.test.context.assertj
import org.springframework.boot.test.context.assertj.ApplicationContextAssertProvider;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.assertj.ApplicationContextAssert;
import org.springframework.boot.test.context.assertj.ApplicationContextAssert.Scope;
import static org.assertj.core.api.Assertions.assertThat;Full Package: org.springframework.boot.test.context.assertj.ApplicationContextAssertProvider
Base interface for application contexts that provide AssertJ assertion support. This interface extends ApplicationContext, AssertProvider, and Closeable, serving as the foundation for all assertable context types.
/**
* Base interface for application contexts that provide AssertJ assertion support
* @param <C> the application context type
* @since 2.0.0
*/
public interface ApplicationContextAssertProvider<C extends ApplicationContext>
extends ApplicationContext, AssertProvider<ApplicationContextAssert<C>>, Closeable {
/**
* Return an assert for AssertJ
* @return an AssertJ assert
* @deprecated since 2.0.0 - to prevent accidental use. Prefer standard AssertJ assertThat(context) calls instead
*/
@Deprecated(since = "2.0.0", forRemoval = false)
@Override
ApplicationContextAssert<C> assertThat();
/**
* Return the original source ApplicationContext
* @return the source application context
* @throws IllegalStateException if the source context failed to start
*/
C getSourceApplicationContext();
/**
* Return the original source ApplicationContext, casting it to the requested type
* @param <T> the context type
* @param requiredType the required context type
* @return the source application context
* @throws IllegalStateException if the source context failed to start
*/
<T extends C> T getSourceApplicationContext(Class<T> requiredType);
/**
* Return the failure that caused application context to fail or null if the context started without issue
* @return the startup failure or null
*/
Throwable getStartupFailure();
/**
* Close the context
*/
@Override
void close();
/**
* Factory method to create a new ApplicationContextAssertProvider instance
* @param <T> the assert provider type
* @param <C> the context type
* @param type the type of ApplicationContextAssertProvider required (must be an interface)
* @param contextType the type of ApplicationContext being managed (must be an interface)
* @param contextSupplier a supplier that will either return a fully configured ApplicationContext or throw an exception if the context fails to start
* @return an ApplicationContextAssertProvider instance
*/
static <T extends ApplicationContextAssertProvider<C>, C extends ApplicationContext> T get(
Class<T> type,
Class<? extends C> contextType,
Supplier<? extends C> contextSupplier);
/**
* Factory method to create a new ApplicationContextAssertProvider instance with additional context interfaces
* @param <T> the assert provider type
* @param <C> the context type
* @param type the type of ApplicationContextAssertProvider required (must be an interface)
* @param contextType the type of ApplicationContext being managed (must be an interface)
* @param contextSupplier a supplier that will either return a fully configured ApplicationContext or throw an exception if the context fails to start
* @param additionalContextInterfaces any additional context interfaces to add to the proxy
* @return an ApplicationContextAssertProvider instance
* @since 3.4.0
*/
static <T extends ApplicationContextAssertProvider<C>, C extends ApplicationContext> T get(
Class<T> type,
Class<? extends C> contextType,
Supplier<? extends C> contextSupplier,
Class<?>... additionalContextInterfaces);
}Full Package: org.springframework.boot.test.context.assertj.AssertableApplicationContext
ApplicationContext that provides AssertJ assertions support.
public interface AssertableApplicationContext
extends ApplicationContextAssertProvider<ConfigurableApplicationContext>,
ConfigurableApplicationContext {
/**
* Factory method to create an AssertableApplicationContext
* @param contextSupplier supplier for the application context
* @return AssertableApplicationContext instance
* @since 2.0.0
*/
static AssertableApplicationContext get(Supplier<? extends ConfigurableApplicationContext> contextSupplier);
/**
* Factory method to create an AssertableApplicationContext with additional context interfaces
* @param contextSupplier supplier for the application context
* @param additionalContextInterfaces any additional context interfaces to add to the proxy
* @return AssertableApplicationContext instance
* @since 3.4.0
*/
static AssertableApplicationContext get(Supplier<? extends ConfigurableApplicationContext> contextSupplier, Class<?>... additionalContextInterfaces);
}Full Package: org.springframework.boot.test.context.assertj.AssertableWebApplicationContext
WebApplicationContext that provides AssertJ assertions support.
public interface AssertableWebApplicationContext
extends ApplicationContextAssertProvider<ConfigurableWebApplicationContext>,
ConfigurableWebApplicationContext {
/**
* Factory method to create an AssertableWebApplicationContext
* @param contextSupplier supplier for the web application context
* @return AssertableWebApplicationContext instance
* @since 2.0.0
*/
static AssertableWebApplicationContext get(Supplier<? extends ConfigurableWebApplicationContext> contextSupplier);
/**
* Factory method to create an AssertableWebApplicationContext with additional context interfaces
* @param contextSupplier supplier for the web application context
* @param additionalContextInterfaces any additional context interfaces to add to the proxy
* @return AssertableWebApplicationContext instance
* @since 3.4.0
*/
static AssertableWebApplicationContext get(Supplier<? extends ConfigurableWebApplicationContext> contextSupplier, Class<?>... additionalContextInterfaces);
}Full Package: org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext
ReactiveWebApplicationContext that provides AssertJ assertions support.
public interface AssertableReactiveWebApplicationContext
extends ApplicationContextAssertProvider<ConfigurableReactiveWebApplicationContext>,
ConfigurableReactiveWebApplicationContext {
/**
* Factory method to create an AssertableReactiveWebApplicationContext
* @param contextSupplier supplier for the reactive web application context
* @return AssertableReactiveWebApplicationContext instance
* @since 2.0.0
*/
static AssertableReactiveWebApplicationContext get(Supplier<? extends ConfigurableReactiveWebApplicationContext> contextSupplier);
/**
* Factory method to create an AssertableReactiveWebApplicationContext with additional context interfaces
* @param contextSupplier supplier for the reactive web application context
* @param additionalContextInterfaces any additional context interfaces to add to the proxy
* @return AssertableReactiveWebApplicationContext instance
* @since 3.4.0
*/
static AssertableReactiveWebApplicationContext get(Supplier<? extends ConfigurableReactiveWebApplicationContext> contextSupplier, Class<?>... additionalContextInterfaces);
}Full Package: org.springframework.boot.test.context.assertj.ApplicationContextAssert<C>
Fluent assertions for ApplicationContext testing.
public class ApplicationContextAssert<C extends ApplicationContext> {
// Bean existence
ApplicationContextAssert<C> hasBean(String name);
ApplicationContextAssert<C> hasSingleBean(Class<?> type);
ApplicationContextAssert<C> hasSingleBean(Class<?> type, Scope scope);
ApplicationContextAssert<C> doesNotHaveBean(Class<?> type);
ApplicationContextAssert<C> doesNotHaveBean(Class<?> type, Scope scope);
ApplicationContextAssert<C> doesNotHaveBean(String name);
// Bean retrieval for further assertions
<T> AbstractObjectAssert<?, T> getBean(Class<T> type);
<T> AbstractObjectAssert<?, T> getBean(Class<T> type, Scope scope);
AbstractObjectAssert<?, Object> getBean(String name);
<T> AbstractObjectAssert<?, T> getBean(String name, Class<T> type);
<T> MapAssert<String, T> getBeans(Class<T> type);
<T> MapAssert<String, T> getBeans(Class<T> type, Scope scope);
<T> AbstractObjectArrayAssert<?, String> getBeanNames(Class<T> type);
// Failure assertions
ApplicationContextAssert<C> hasFailed();
ApplicationContextAssert<C> hasNotFailed();
AbstractThrowableAssert<?, ? extends Throwable> getFailure();
enum Scope {
NO_ANCESTORS, // Current context only
INCLUDE_ANCESTORS // Include parent contexts
}
}import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@Configuration
class MyConfig {
@Bean
public MyService myService() {
return new MyService();
}
}
class ContextAssertTest {
private final ApplicationContextRunner contextRunner =
new ApplicationContextRunner()
.withUserConfiguration(MyConfig.class);
@Test
void testBeanExists() {
contextRunner.run(context -> {
// Bean existence
assertThat(context).hasBean("myService");
assertThat(context).hasSingleBean(MyService.class);
// Bean absence
assertThat(context).doesNotHaveBean(OtherService.class);
});
}
@Test
void testBeanProperties() {
contextRunner.run(context -> {
// Get bean for assertions
assertThat(context).getBean(MyService.class)
.isNotNull()
.extracting("initialized")
.isEqualTo(true);
});
}
@Test
void testMultipleBeans() {
contextRunner.run(context -> {
// Get all beans of type
assertThat(context).getBeans(MyPlugin.class)
.hasSize(3)
.containsKeys("plugin1", "plugin2", "plugin3");
});
}
}@Test
void testContextFailure() {
new ApplicationContextRunner()
.withUserConfiguration(InvalidConfig.class)
.run(context -> {
assertThat(context).hasFailed();
assertThat(context).getFailure()
.isInstanceOf(BeanCreationException.class)
.hasMessageContaining("required bean");
});
}
@Test
void testContextSuccess() {
contextRunner.run(context -> {
assertThat(context).hasNotFailed();
});
}@Test
void testWithParentContext() {
ApplicationContext parent = new AnnotationConfigApplicationContext(ParentConfig.class);
new ApplicationContextRunner()
.withParent(parent)
.withUserConfiguration(ChildConfig.class)
.run(context -> {
// Current context only
assertThat(context)
.getBeans(MyService.class, Scope.NO_ANCESTORS)
.hasSize(1);
// Include parent
assertThat(context)
.getBeans(MyService.class, Scope.INCLUDE_ANCESTORS)
.hasSize(2);
});
}@Test
void testChainedAssertions() {
contextRunner.run(context -> {
assertThat(context)
.hasSingleBean(MyService.class)
.hasBean("myService")
.doesNotHaveBean(OtherService.class);
assertThat(context).getBean(MyService.class)
.isNotNull()
.hasFieldOrPropertyWithValue("name", "default")
.extracting("value")
.isEqualTo("expected");
});
}@Test
void testBeanNames() {
contextRunner
.withUserConfiguration(MultiPluginConfig.class)
.run(context -> {
assertThat(context).getBeanNames(Plugin.class)
.hasSize(3)
.contains("plugin1", "plugin2", "plugin3")
.allMatch(name -> name.startsWith("plugin"));
});
}@Configuration
class MultiServiceConfig {
@Bean
public DataProcessor primaryProcessor() {
return new PrimaryDataProcessor();
}
@Bean
public DataProcessor secondaryProcessor() {
return new SecondaryDataProcessor();
}
@Bean
public DataProcessor backupProcessor() {
return new BackupDataProcessor();
}
}
@Test
void testMultipleBeansOfSameType() {
new ApplicationContextRunner()
.withUserConfiguration(MultiServiceConfig.class)
.run(context -> {
assertThat(context).getBeans(DataProcessor.class)
.hasSize(3)
.containsKeys("primaryProcessor", "secondaryProcessor", "backupProcessor");
assertThat(context).getBeans(DataProcessor.class)
.extractingByKey("primaryProcessor")
.isInstanceOf(PrimaryDataProcessor.class);
});
}@Test
void testBeanPropertyExtraction() {
contextRunner
.withPropertyValues("service.name=TestService", "service.port=8080")
.withUserConfiguration(ServiceConfig.class)
.run(context -> {
assertThat(context).getBean(MyService.class)
.extracting("name", "port", "initialized")
.containsExactly("TestService", 8080, true);
});
}@Test
void testNestedBeanStructure() {
contextRunner
.withUserConfiguration(CompositeServiceConfig.class)
.run(context -> {
assertThat(context).getBean(CompositeService.class)
.isNotNull()
.extracting("innerService")
.isNotNull()
.extracting("database")
.isNotNull()
.extracting("connectionPool")
.satisfies(pool -> {
assertThat(pool).hasFieldOrPropertyWithValue("maxConnections", 10);
});
});
}@Test
void testConditionalBeanCreation() {
// When property is set
contextRunner
.withPropertyValues("feature.enabled=true")
.withUserConfiguration(ConditionalConfig.class)
.run(context -> {
assertThat(context)
.hasSingleBean(FeatureService.class)
.hasBean("featureService");
});
// When property is not set
contextRunner
.withUserConfiguration(ConditionalConfig.class)
.run(context -> {
assertThat(context)
.doesNotHaveBean(FeatureService.class)
.doesNotHaveBean("featureService");
});
}@Test
void testBeanScope() {
contextRunner
.withUserConfiguration(ScopedBeansConfig.class)
.run(context -> {
// Singleton bean
Object bean1 = context.getBean("singletonBean");
Object bean2 = context.getBean("singletonBean");
assertThat(bean1).isSameAs(bean2);
// Prototype bean
Object proto1 = context.getBean("prototypeBean");
Object proto2 = context.getBean("prototypeBean");
assertThat(proto1).isNotSameAs(proto2);
});
}@Test
void testParentContextBeans() {
ApplicationContext parent = new AnnotationConfigApplicationContext(ParentConfig.class);
new ApplicationContextRunner()
.withParent(parent)
.withUserConfiguration(ChildConfig.class)
.run(context -> {
// Bean from child context only
assertThat(context)
.hasSingleBean(ChildService.class, Scope.NO_ANCESTORS);
// Beans from both contexts
assertThat(context)
.getBeans(ParentService.class, Scope.INCLUDE_ANCESTORS)
.hasSize(1);
assertThat(context).getBean(ChildService.class)
.extracting("parentService")
.isNotNull();
});
}@Test
void testBeanLifecycle() {
contextRunner
.withUserConfiguration(LifecycleConfig.class)
.run(context -> {
LifecycleBean bean = context.getBean(LifecycleBean.class);
assertThat(bean.isInitialized()).isTrue();
assertThat(bean.getInitCount()).isEqualTo(1);
// Context will be closed automatically
});
}@Configuration
class PrimaryBeanConfig {
@Bean
@Primary
public DatabaseService primary() {
return new PostgresService();
}
@Bean
public DatabaseService fallback() {
return new H2Service();
}
}
@Test
void testPrimaryBeanSelection() {
new ApplicationContextRunner()
.withUserConfiguration(PrimaryBeanConfig.class)
.run(context -> {
assertThat(context).getBeans(DatabaseService.class)
.hasSize(2);
assertThat(context).getBean(DatabaseService.class)
.isInstanceOf(PostgresService.class);
});
}@Test
void testBeanDependencies() {
contextRunner
.withUserConfiguration(DependentBeansConfig.class)
.run(context -> {
ServiceA serviceA = context.getBean(ServiceA.class);
ServiceB serviceB = context.getBean(ServiceB.class);
ServiceC serviceC = context.getBean(ServiceC.class);
assertThat(serviceB.getServiceA()).isSameAs(serviceA);
assertThat(serviceC.getServiceA()).isSameAs(serviceA);
assertThat(serviceC.getServiceB()).isSameAs(serviceB);
});
}@Test
void testAutoConfigurationOrder() {
new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
DatabaseAutoConfiguration.class,
CachingAutoConfiguration.class,
SecurityAutoConfiguration.class
))
.run(context -> {
assertThat(context)
.hasSingleBean(DataSource.class)
.hasSingleBean(CacheManager.class)
.hasSingleBean(SecurityConfig.class);
// Verify auto-configuration ordering
SecurityConfig security = context.getBean(SecurityConfig.class);
assertThat(security.getDataSource()).isNotNull();
assertThat(security.getCacheManager()).isNotNull();
});
}@Test
void testEnvironmentPropertiesAffectBeans() {
contextRunner
.withPropertyValues(
"app.name=TestApp",
"app.version=1.0.0",
"app.debug=true"
)
.withUserConfiguration(AppConfig.class)
.run(context -> {
assertThat(context).getBean(AppInfo.class)
.hasFieldOrPropertyWithValue("name", "TestApp")
.hasFieldOrPropertyWithValue("version", "1.0.0")
.hasFieldOrPropertyWithValue("debug", true);
});
}@Test
void testCollectionBeans() {
contextRunner
.withUserConfiguration(CollectionConfig.class)
.run(context -> {
assertThat(context).getBean("userList", List.class)
.hasSize(3)
.extracting("name")
.contains("Alice", "Bob", "Charlie");
assertThat(context).getBean("configMap", Map.class)
.containsKeys("key1", "key2", "key3")
.containsEntry("key1", "value1");
});
}@Test
void testExpectedStartupFailure() {
new ApplicationContextRunner()
.withUserConfiguration(InvalidConfig.class)
.run(context -> {
assertThat(context).hasFailed();
assertThat(context).getFailure()
.isInstanceOf(BeanCreationException.class)
.hasMessageContaining("Could not autowire")
.hasMessageContaining("No qualifying bean");
});
}@Test
void testMissingDependency() {
new ApplicationContextRunner()
.withUserConfiguration(DependentServiceConfig.class)
// Not providing required dependency
.run(context -> {
assertThat(context).hasFailed();
assertThat(context).getFailure()
.hasCauseInstanceOf(NoSuchBeanDefinitionException.class)
.hasStackTraceContaining("DataSource");
});
}@Test
void testCircularDependencyFailure() {
new ApplicationContextRunner()
.withUserConfiguration(CircularConfig.class)
.run(context -> {
assertThat(context).hasFailed();
assertThat(context).getFailure()
.isInstanceOf(BeanCurrentlyInCreationException.class)
.hasMessageContaining("circular reference")
.hasMessageContaining("ServiceA")
.hasMessageContaining("ServiceB");
});
}@Test
void testBeanValidationFailure() {
new ApplicationContextRunner()
.withPropertyValues("service.timeout=-1") // Invalid value
.withUserConfiguration(ValidatedServiceConfig.class)
.run(context -> {
assertThat(context).hasFailed();
assertThat(context).getFailure()
.getRootCause()
.isInstanceOf(ConstraintViolationException.class)
.hasMessageContaining("timeout")
.hasMessageContaining("must be positive");
});
}@Test
void testPropertyBindingFailure() {
new ApplicationContextRunner()
.withPropertyValues("service.port=invalid") // Should be int
.withUserConfiguration(ServiceConfig.class)
.run(context -> {
assertThat(context).hasFailed();
assertThat(context).getFailure()
.hasMessageContaining("Failed to bind properties")
.hasMessageContaining("service.port");
});
}@Test
void testConditionalFailure() {
// Should fail when required class is missing
new ApplicationContextRunner()
.withClassLoader(new FilteredClassLoader(DataSource.class))
.withUserConfiguration(DataSourceRequiringConfig.class)
.run(context -> {
assertThat(context).hasFailed();
assertThat(context).getFailure()
.hasMessageContaining("DataSource")
.hasCauseInstanceOf(NoClassDefFoundError.class);
});
}Issue: assertThat(context) doesn't have bean methods
import static org.assertj.core.api.Assertions.assertThat;Issue: hasSingleBean fails with multiple beans
Issue: Bean assertions fail unexpectedly