Spring Security Test provides comprehensive testing utilities for Spring Security applications with mock authentication, security context testing, and web security testing features.
—
Core testing annotations for declarative security context management, providing method and class-level authentication setup without complex configuration. These annotations integrate with Spring Test's TestExecutionListener framework to automatically establish security contexts before test execution.
Creates a mock authenticated user with customizable username, password, roles, and authorities.
/**
* Creates a mock authenticated user for testing
* Can be applied to test methods or test classes
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@WithSecurityContext(factory = WithMockUserSecurityContextFactory.class)
public @interface WithMockUser {
/** Username for the mock user (default: "user") */
String value() default "user";
/** Username for the mock user (takes precedence over value()) */
String username() default "";
/** Password for the mock user (default: "password") */
String password() default "password";
/** User roles, automatically prefixed with "ROLE_" (default: {"USER"}) */
String[] roles() default {"USER"};
/** Granted authorities, not automatically prefixed */
String[] authorities() default {};
/** When to establish the security context */
TestExecutionEvent setupBefore() default TestExecutionEvent.TEST_METHOD;
}Usage Examples:
// Method-level with default user
@Test
@WithMockUser
public void testWithDefaultUser() {
// Test runs with username="user", roles={"USER"}
}
// Custom username and roles
@Test
@WithMockUser(username = "admin", roles = {"ADMIN", "USER"})
public void testWithAdmin() {
// Test runs with admin privileges
}
// Using authorities instead of roles
@Test
@WithMockUser(authorities = {"READ_PRIVILEGES", "WRITE_PRIVILEGES"})
public void testWithCustomAuthorities() {
// Test runs with specific authorities (no ROLE_ prefix)
}
// Class-level annotation applies to all methods
@WithMockUser(roles = "MANAGER")
public class ManagerTests {
@Test
public void testManagerFeature() {
// Inherits manager role from class annotation
}
@Test
@WithAnonymousUser // Override class-level annotation
public void testAnonymousAccess() {
// Runs as anonymous user
}
}Creates an anonymous authentication for testing scenarios where no authentication is present.
/**
* Creates anonymous authentication for testing
* Can be applied to test methods or test classes
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@WithSecurityContext(factory = WithAnonymousUserSecurityContextFactory.class)
public @interface WithAnonymousUser {
/** When to establish the security context */
TestExecutionEvent setupBefore() default TestExecutionEvent.TEST_METHOD;
}Usage Examples:
@Test
@WithAnonymousUser
public void testAnonymousAccess() {
// Test runs with anonymous authentication
// Useful for testing public endpoints or access denied scenarios
}
// Override class-level security annotation
@WithMockUser(roles = "USER")
public class UserTests {
@Test
@WithAnonymousUser
public void testPublicEndpoint() {
// Overrides class-level @WithMockUser
}
}Loads a user via UserDetailsService for more realistic testing scenarios using actual user data.
/**
* Loads user via UserDetailsService for testing
* Requires a UserDetailsService bean in the test context
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@WithSecurityContext(factory = WithUserDetailsSecurityContextFactory.class)
public @interface WithUserDetails {
/** Username to lookup via UserDetailsService (default: "user") */
String value() default "user";
/** Specific UserDetailsService bean name to use */
String userDetailsServiceBeanName() default "";
/** When to establish the security context */
TestExecutionEvent setupBefore() default TestExecutionEvent.TEST_METHOD;
}Usage Examples:
@Test
@WithUserDetails("john.doe@example.com")
public void testWithRealUser() {
// Loads user "john.doe@example.com" via UserDetailsService
// Uses actual user data including roles and authorities
}
@Test
@WithUserDetails(value = "admin", userDetailsServiceBeanName = "customUserDetailsService")
public void testWithCustomService() {
// Uses specific UserDetailsService bean
}Meta-annotation that enables only Spring Security test execution listeners, useful when testing security features without a full application context.
/**
* Meta-annotation that enables Spring Security TestExecutionListeners
* Use when testing security without full Spring context setup
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@TestExecutionListeners(
inheritListeners = false,
listeners = {
WithSecurityContextTestExecutionListener.class,
ReactorContextTestExecutionListener.class
}
)
public @interface SecurityTestExecutionListeners {
}Usage Examples:
// Use when you only need security testing without full Spring Boot context
@SecurityTestExecutionListeners
public class SecurityUnitTests {
@Test
@WithMockUser(roles = "USER")
public void testSecurityLogic() {
// Test security-related logic without full application context
// Only security test execution listeners are enabled
}
}
// Useful for lightweight security testing
@SecurityTestExecutionListeners
public class AuthenticationUnitTests {
@Test
@WithUserDetails("testuser")
public void testUserDetailsLogic() {
// Tests user details without loading full Spring context
// Performance benefits for focused security tests
}
}Meta-annotation for creating custom security context annotations with custom factory implementations.
/**
* Meta-annotation for creating custom security context annotations
* Requires a factory implementation
*/
@Target({ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface WithSecurityContext {
/** Factory class that creates the SecurityContext */
Class<? extends WithSecurityContextFactory<? extends Annotation>> factory();
/** When to establish the security context */
TestExecutionEvent setupBefore() default TestExecutionEvent.TEST_METHOD;
}Usage Examples:
// Custom annotation definition
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = WithCustomUserSecurityContextFactory.class)
public @interface WithCustomUser {
String username() default "customUser";
String department() default "IT";
}
// Custom factory implementation
public class WithCustomUserSecurityContextFactory
implements WithSecurityContextFactory<WithCustomUser> {
@Override
public SecurityContext createSecurityContext(WithCustomUser annotation) {
SecurityContext context = SecurityContextHolder.createEmptyContext();
// Create custom authentication with department-specific authorities
List<GrantedAuthority> authorities = Arrays.asList(
new SimpleGrantedAuthority("ROLE_USER"),
new SimpleGrantedAuthority("DEPT_" + annotation.department().toUpperCase())
);
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(
annotation.username(),
"password",
authorities
);
context.setAuthentication(auth);
return context;
}
}
// Usage of custom annotation
@Test
@WithCustomUser(username = "alice", department = "FINANCE")
public void testCustomUser() {
// Test runs with custom user having ROLE_USER and DEPT_FINANCE authorities
}Factory interface for creating security contexts from annotations.
/**
* Factory interface for creating SecurityContext from annotation
* @param <A> The annotation type this factory handles
*/
public interface WithSecurityContextFactory<A extends Annotation> {
/**
* Create SecurityContext from the provided annotation
* @param annotation The annotation instance with configuration
* @return SecurityContext to be used for the test
*/
SecurityContext createSecurityContext(A annotation);
}// Factory for @WithMockUser
public class WithMockUserSecurityContextFactory
implements WithSecurityContextFactory<WithMockUser> {
public SecurityContext createSecurityContext(WithMockUser withUser);
}
// Factory for @WithAnonymousUser
public class WithAnonymousUserSecurityContextFactory
implements WithSecurityContextFactory<WithAnonymousUser> {
public SecurityContext createSecurityContext(WithAnonymousUser withAnonymousUser);
}
// Factory for @WithUserDetails
public class WithUserDetailsSecurityContextFactory
implements WithSecurityContextFactory<WithUserDetails> {
public SecurityContext createSecurityContext(WithUserDetails withUserDetails);
}Defines when the security context should be established during test execution.
/**
* Defines when SecurityContext should be established
*/
public enum TestExecutionEvent {
/** Before test method execution (default) */
TEST_METHOD,
/** Before test execution, after setup methods */
TEST_EXECUTION
}The test execution listener that processes security context annotations.
/**
* TestExecutionListener that processes @WithSecurityContext annotations
* Order: 10000 (runs after most other listeners)
*/
public class WithSecurityContextTestExecutionListener implements TestExecutionListener {
// Processes annotations before test method/execution
// Clears security context after test completion
}setupBefore value@WithMockUser(roles = "USER") // Class-level default
public class SecurityTests {
@Test
public void testUserFeature() {
// Uses class-level USER role
}
@Test
@WithMockUser(roles = "ADMIN") // Override for this method
public void testAdminFeature() {
// Uses ADMIN role
}
@Test
@WithAnonymousUser // Override to anonymous
public void testPublicAccess() {
// No authentication
}
}@ParameterizedTest
@ValueSource(strings = {"user1", "user2", "admin"})
@WithUserDetails // Uses parameter value as username
public void testMultipleUsers(String username) {
// Test runs for each username via UserDetailsService
}@WithMockUser(roles = "USER")
public class SecurityNestedTests {
@Nested
@WithMockUser(roles = "ADMIN") // Overrides parent class annotation
class AdminTests {
@Test
public void testAdminFeature() {
// Runs with ADMIN role
}
}
@Nested
class UserTests {
@Test
public void testUserFeature() {
// Inherits USER role from parent class
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-springframework-security--spring-security-test