CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springframework--spring-test

Spring TestContext Framework for comprehensive integration testing of Spring applications

Overview
Eval results
Files

junit-integration.mddocs/

JUnit Integration

Spring Test provides seamless integration with JUnit Jupiter (JUnit 5) through the SpringExtension and composite annotations. This integration enables Spring-specific features like dependency injection, transaction management, and context configuration in JUnit tests.

Capabilities

Spring Extension

The core JUnit Jupiter extension that integrates Spring TestContext Framework with JUnit 5.

/**
 * SpringExtension integrates the Spring TestContext Framework into JUnit 5's Jupiter programming model.
 * 
 * To use this extension, simply annotate a JUnit Jupiter based test class with @ExtendWith(SpringExtension.class)
 * or use composite annotations like @SpringJUnitConfig.
 */
public class SpringExtension implements BeforeAllCallback, AfterAllCallback, 
    TestInstancePostProcessor, BeforeEachCallback, AfterEachCallback, 
    BeforeTestExecutionCallback, AfterTestExecutionCallback, ParameterResolver {
    
    /**
     * Delegates to TestContextManager.beforeTestClass().
     * @param context the current extension context
     */
    @Override
    public void beforeAll(ExtensionContext context) throws Exception;
    
    /**
     * Delegates to TestContextManager.afterTestClass().
     * @param context the current extension context
     */
    @Override
    public void afterAll(ExtensionContext context) throws Exception;
    
    /**
     * Delegates to TestContextManager.prepareTestInstance().
     * @param testInstance the test instance to post-process
     * @param context the current extension context
     */
    @Override
    public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception;
    
    /**
     * Delegates to TestContextManager.beforeTestMethod().
     * @param context the current extension context
     */
    @Override
    public void beforeEach(ExtensionContext context) throws Exception;
    
    /**
     * Delegates to TestContextManager.beforeTestExecution().
     * @param context the current extension context
     */
    @Override
    public void beforeTestExecution(ExtensionContext context) throws Exception;
    
    /**
     * Delegates to TestContextManager.afterTestExecution().
     * @param context the current extension context
     */
    @Override
    public void afterTestExecution(ExtensionContext context) throws Exception;
    
    /**
     * Delegates to TestContextManager.afterTestMethod().
     * @param context the current extension context
     */
    @Override
    public void afterEach(ExtensionContext context) throws Exception;
    
    /**
     * Resolve parameters from the Spring ApplicationContext if the parameter is of a supported type.
     * @param parameterContext the context for the parameter for which an argument should be resolved
     * @param extensionContext the extension context for the Executable about to be invoked
     * @return true if this resolver can resolve an argument for the parameter
     */
    @Override
    public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext);
    
    /**
     * Resolve a parameter from the Spring ApplicationContext.
     * @param parameterContext the context for the parameter for which an argument should be resolved
     * @param extensionContext the extension context for the Executable about to be invoked
     * @return the resolved argument for the parameter
     * @throws ParameterResolutionException if the parameter cannot be resolved
     */
    @Override
    public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext);
}

Composite Annotations

Convenient composed annotations that combine Spring testing features with JUnit Jupiter.

/**
 * @SpringJUnitConfig is a composed annotation that combines @ExtendWith(SpringExtension.class) 
 * from JUnit Jupiter with @ContextConfiguration from the Spring TestContext Framework.
 */
@ExtendWith(SpringExtension.class)
@ContextConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface SpringJUnitConfig {
    
    /**
     * Alias for classes().
     * @return an array of configuration classes
     */
    @AliasFor(annotation = ContextConfiguration.class, attribute = "classes")
    Class<?>[] value() default {};
    
    /**
     * The component classes to use for loading an ApplicationContext.
     * @return an array of configuration classes
     */
    @AliasFor(annotation = ContextConfiguration.class, attribute = "classes")
    Class<?>[] classes() default {};
    
    /**
     * The resource locations to use for loading an ApplicationContext.
     * @return an array of resource locations
     */
    @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    String[] locations() default {};
    
    /**
     * The application context initializer classes to use for initializing a ConfigurableApplicationContext.
     * @return an array of initializer classes
     */
    @AliasFor(annotation = ContextConfiguration.class, attribute = "initializers")
    Class<? extends ApplicationContextInitializer<?>>[] initializers() default {};
    
    /**
     * Whether or not resource locations or component classes from test superclasses should be inherited.
     * @return true if locations should be inherited
     */
    @AliasFor(annotation = ContextConfiguration.class, attribute = "inheritLocations")
    boolean inheritLocations() default true;
    
    /**
     * Whether or not context initializers from test superclasses should be inherited.
     * @return true if initializers should be inherited
     */
    @AliasFor(annotation = ContextConfiguration.class, attribute = "inheritInitializers")
    boolean inheritInitializers() default true;
    
    /**
     * The name of the context hierarchy level represented by this configuration.
     * @return the context hierarchy level name
     */
    @AliasFor(annotation = ContextConfiguration.class, attribute = "name")
    String name() default "";
}

/**
 * @SpringJUnitWebConfig is a composed annotation that combines @SpringJUnitConfig 
 * with @WebAppConfiguration from the Spring TestContext Framework.
 */
@SpringJUnitConfig
@WebAppConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface SpringJUnitWebConfig {
    
    /**
     * Alias for classes().
     * @return an array of configuration classes
     */
    @AliasFor(annotation = SpringJUnitConfig.class, attribute = "classes")
    Class<?>[] value() default {};
    
    /**
     * The component classes to use for loading an ApplicationContext.
     * @return an array of configuration classes
     */
    @AliasFor(annotation = SpringJUnitConfig.class, attribute = "classes")
    Class<?>[] classes() default {};
    
    /**
     * The resource locations to use for loading an ApplicationContext.
     * @return an array of resource locations
     */
    @AliasFor(annotation = SpringJUnitConfig.class, attribute = "locations")
    String[] locations() default {};
    
    /**
     * The application context initializer classes to use for initializing a ConfigurableApplicationContext.
     * @return an array of initializer classes
     */
    @AliasFor(annotation = SpringJUnitConfig.class, attribute = "initializers")
    Class<? extends ApplicationContextInitializer<?>>[] initializers() default {};
    
    /**
     * Whether or not resource locations or component classes from test superclasses should be inherited.
     * @return true if locations should be inherited
     */
    @AliasFor(annotation = SpringJUnitConfig.class, attribute = "inheritLocations")
    boolean inheritLocations() default true;
    
    /**
     * Whether or not context initializers from test superclasses should be inherited.
     * @return true if initializers should be inherited
     */
    @AliasFor(annotation = SpringJUnitConfig.class, attribute = "inheritInitializers")
    boolean inheritInitializers() default true;
    
    /**
     * The name of the context hierarchy level represented by this configuration.
     * @return the context hierarchy level name
     */
    @AliasFor(annotation = SpringJUnitConfig.class, attribute = "name")
    String name() default "";
    
    /**
     * The resource path to the root of the web application.
     * @return the resource path for the web application
     */
    @AliasFor(annotation = WebAppConfiguration.class, attribute = "value")
    String resourcePath() default "src/main/webapp";
}

Conditional Test Execution

JUnit Jupiter extensions for conditional test execution based on Spring profiles and SpEL expressions.

/**
 * @EnabledIf is used to signal that the annotated test class or test method is enabled 
 * and should be executed if the supplied SpEL expression evaluates to true.
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ExtendWith(SpringJUnitCondition.class)
public @interface EnabledIf {
    
    /**
     * The SpEL expression to evaluate.
     * @return the SpEL expression
     */
    String expression();
    
    /**
     * The reason this test is enabled.
     * @return the reason
     */
    String reason() default "";
    
    /**
     * Whether the ApplicationContext should be eagerly loaded to evaluate the expression.
     * @return true if the context should be loaded
     */
    boolean loadContext() default false;
}

/**
 * @DisabledIf is used to signal that the annotated test class or test method is disabled 
 * and should not be executed if the supplied SpEL expression evaluates to true.
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ExtendWith(SpringJUnitCondition.class)
public @interface DisabledIf {
    
    /**
     * The SpEL expression to evaluate.
     * @return the SpEL expression
     */
    String expression();
    
    /**
     * The reason this test is disabled.
     * @return the reason
     */
    String reason() default "";
    
    /**
     * Whether the ApplicationContext should be eagerly loaded to evaluate the expression.
     * @return true if the context should be loaded
     */
    boolean loadContext() default false;
}

/**
 * SpringJUnitCondition is a JUnit Jupiter ExecutionCondition that supports the @EnabledIf and @DisabledIf annotations.
 */
public class SpringJUnitCondition implements ExecutionCondition {
    
    /**
     * Evaluate the condition for the given extension context.
     * @param context the current extension context
     * @return the evaluation result
     */
    @Override
    public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context);
}

Parameter Resolution

Support for dependency injection in test method parameters.

/**
 * ApplicationContextParameterResolver resolves method parameters of type ApplicationContext 
 * (or sub-types thereof) for JUnit Jupiter test methods.
 */
public class ApplicationContextParameterResolver implements ParameterResolver {
    
    /**
     * Determine if this resolver supports the given parameter.
     * @param parameterContext the parameter context
     * @param extensionContext the extension context
     * @return true if the parameter is supported
     */
    @Override
    public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext);
    
    /**
     * Resolve the parameter from the ApplicationContext.
     * @param parameterContext the parameter context
     * @param extensionContext the extension context
     * @return the resolved parameter value
     */
    @Override
    public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext);
}

Usage Examples:

import org.springframework.test.context.junit.jupiter.*;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;

// Basic Spring JUnit integration
@SpringJUnitConfig(AppConfig.class)
class UserServiceIntegrationTest {
    
    @Autowired
    private UserService userService;
    
    @Test
    void shouldInjectDependencies() {
        assertThat(userService).isNotNull();
        
        User user = new User("John", "john@example.com");
        User saved = userService.save(user);
        assertThat(saved.getId()).isNotNull();
    }
    
    @Test
    void shouldSupportParameterInjection(UserRepository userRepository) {
        // Parameters can be injected from ApplicationContext
        assertThat(userRepository).isNotNull();
        
        long count = userRepository.count();
        assertThat(count).isGreaterThanOrEqualTo(0);
    }
}

// Web application testing
@SpringJUnitWebConfig(WebConfig.class)
class WebControllerIntegrationTest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @Autowired
    private WebApplicationContext webApplicationContext;
    
    @Test
    void shouldLoadWebApplicationContext() {
        assertThat(webApplicationContext).isNotNull();
        assertThat(webApplicationContext.getServletContext()).isNotNull();
    }
    
    @Test
    void shouldPerformWebRequests() throws Exception {
        mockMvc.perform(get("/users"))
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON));
    }
}

// Multiple configuration sources
@SpringJUnitConfig(locations = {"classpath:app-config.xml", "classpath:test-config.xml"})
class XmlConfigIntegrationTest {
    
    @Autowired
    private DataSource dataSource;
    
    @Test
    void shouldLoadXmlConfiguration() {
        assertThat(dataSource).isNotNull();
    }
}

// Conditional test execution
@SpringJUnitConfig(ConditionalTestConfig.class)
class ConditionalExecutionTest {
    
    @Test
    @EnabledIf("#{environment.acceptsProfiles('integration')}")
    void shouldRunOnlyInIntegrationProfile() {
        // This test runs only when 'integration' profile is active
    }
    
    @Test
    @EnabledIf("#{systemProperties['os.name'].toLowerCase().contains('linux')}")
    void shouldRunOnlyOnLinux() {
        // This test runs only on Linux systems
    }
    
    @Test
    @DisabledIf("#{T(java.time.LocalTime).now().hour < 9}")
    void shouldNotRunBeforeNineAM() {
        // This test is disabled before 9 AM
    }
    
    @Test
    @EnabledIf(expression = "#{@testDataService.hasTestData()}", loadContext = true)
    void shouldRunWhenTestDataExists() {
        // This test runs only when test data exists (requires context loading)
    }
}

// Nested test classes with Spring
@SpringJUnitConfig(NestedTestConfig.class)
class NestedSpringTests {
    
    @Autowired
    private UserService userService;
    
    @Test
    void shouldHaveUserService() {
        assertThat(userService).isNotNull();
    }
    
    @Nested
    @TestPropertySource(properties = "feature.enabled=true")
    class WhenFeatureEnabled {
        
        @Autowired
        private FeatureService featureService;
        
        @Test
        void shouldEnableFeature() {
            assertThat(featureService.isEnabled()).isTrue();
        }
        
        @Test
        @EnabledIf("#{@featureService.isEnabled()}")
        void shouldRunWhenFeatureIsEnabled() {
            // Test feature-specific behavior
        }
    }
    
    @Nested
    @ActiveProfiles("mock")
    class WithMockProfile {
        
        @Test
        void shouldUseMockBeans() {
            // Tests with mock profile active
        }
    }
}

// Parameterized tests with Spring
@SpringJUnitConfig(ValidationTestConfig.class)
class ParameterizedSpringTest {
    
    @Autowired
    private ValidationService validationService;
    
    @ParameterizedTest
    @ValueSource(strings = {"john@example.com", "jane@test.org", "bob@company.net"})
    void shouldValidateEmails(String email) {
        ValidationResult result = validationService.validateEmail(email);
        assertThat(result.isValid()).isTrue();
    }
    
    @ParameterizedTest
    @CsvSource({
        "John, john@example.com, true",
        "'', invalid-email, false", 
        "Jane, jane@test.org, true"
    })
    void shouldValidateUsers(String name, String email, boolean expectedValid) {
        User user = new User(name, email);
        ValidationResult result = validationService.validateUser(user);
        assertThat(result.isValid()).isEqualTo(expectedValid);
    }
}

// Dynamic tests with Spring context
@SpringJUnitConfig(DynamicTestConfig.class)
class DynamicSpringTests {
    
    @Autowired
    private TestDataService testDataService;
    
    @TestFactory
    Stream<DynamicTest> shouldTestAllUsers() {
        return testDataService.getAllTestUsers().stream()
            .map(user -> DynamicTest.dynamicTest(
                "Testing user: " + user.getName(),
                () -> {
                    assertThat(user.getId()).isNotNull();
                    assertThat(user.getName()).isNotBlank();
                    assertThat(user.getEmail()).contains("@");
                }
            ));
    }
    
    @TestFactory
    Collection<DynamicTest> shouldValidateAllConfigurations(ConfigurationService configService) {
        return configService.getAllConfigurations().stream()
            .map(config -> DynamicTest.dynamicTest(
                "Validating config: " + config.getName(),
                () -> assertThat(configService.isValid(config)).isTrue()
            ))
            .toList();
    }
}

// Test lifecycle callbacks
@SpringJUnitConfig(LifecycleTestConfig.class)
class TestLifecycleExample {
    
    @Autowired
    private DatabaseService databaseService;
    
    @BeforeAll
    static void setupClass() {
        // Class-level setup
        System.setProperty("test.environment", "junit5");
    }
    
    @BeforeEach
    void setUp() {
        // Method-level setup - Spring context is available here
        databaseService.clearCache();
    }
    
    @Test
    void shouldHaveCleanState() {
        assertThat(databaseService.getCacheSize()).isZero();
    }
    
    @AfterEach
    void tearDown() {
        // Method-level cleanup
        databaseService.resetToDefaults();
    }
    
    @AfterAll
    static void tearDownClass() {
        // Class-level cleanup
        System.clearProperty("test.environment");
    }
}

Types

/**
 * Encapsulates the context in which a test is executed, agnostic of the actual testing framework in use.
 * Used by SpringExtension to bridge JUnit Jupiter and Spring TestContext Framework.
 */
public interface TestContext {
    
    /**
     * Get the application context for this test context.
     * @return the application context (never null)
     * @throws IllegalStateException if an error occurs while retrieving the application context
     */
    ApplicationContext getApplicationContext();
    
    /**
     * Get the test class for this test context.
     * @return the test class (never null)  
     */
    Class<?> getTestClass();
    
    /**
     * Get the current test instance for this test context.
     * @return the current test instance (may be null)
     */
    @Nullable
    Object getTestInstance();
    
    /**
     * Get the current test method for this test context.
     * @return the current test method (may be null)
     */
    @Nullable
    Method getTestMethod();
}

/**
 * Strategy interface for resolving test method parameters from a Spring ApplicationContext.
 */
public interface TestContextParameterResolver {
    
    /**
     * Determine if this resolver can resolve the given parameter.
     * @param parameter the parameter to resolve
     * @param testClass the test class
     * @param applicationContext the Spring application context
     * @return true if the parameter can be resolved
     */
    boolean supportsParameter(Parameter parameter, Class<?> testClass, ApplicationContext applicationContext);
    
    /**
     * Resolve the given parameter from the application context.
     * @param parameter the parameter to resolve
     * @param testClass the test class
     * @param applicationContext the Spring application context
     * @return the resolved parameter value
     */
    Object resolveParameter(Parameter parameter, Class<?> testClass, ApplicationContext applicationContext);
}

/**
 * Exception thrown when parameter resolution fails in Spring test context.
 */
public class ParameterResolutionException extends RuntimeException {
    
    /**
     * Create a new ParameterResolutionException.
     * @param message the detail message
     */
    public ParameterResolutionException(String message);
    
    /**
     * Create a new ParameterResolutionException.
     * @param message the detail message
     * @param cause the root cause
     */
    public ParameterResolutionException(String message, @Nullable Throwable cause);
}

Install with Tessl CLI

npx tessl i tessl/maven-org-springframework--spring-test

docs

bean-override-framework.md

index.md

jdbc-testing.md

junit-integration.md

mock-objects.md

testcontext-framework.md

testing-annotations.md

web-testing.md

tile.json