Summary
When using JUnit 5 it seems that setting the setupBefore parameter of @WithUserDetails to TestExecutionEvent.TEST_EXECUTION does not work as intended. In fact it appears that the security context is created before the execution of a @BeforeEach method.
Actual Behavior
I wrote the following test class to showcase the issue
@ExtendWith(SpringExtension.class)
@ContextConfiguration
class WithUserDetailsTest {
private static String USERNAME;
@BeforeEach
void setUp() {
USERNAME = "dummy";
}
@Test
@WithUserDetails(
userDetailsServiceBeanName = "testUserDetailsService",
setupBefore = TestExecutionEvent.TEST_EXECUTION
)
void test() {
TestUserDetails principal = (TestUserDetails) SecurityContextHolder.getContext()
.getAuthentication().getPrincipal();
Assertions.assertNotNull(principal.getUsername());
}
@Configuration
static class TestUserDetailsConfiguration {
@Bean("testUserDetailsService")
UserDetailsService testUserDetailsService() {
return s -> new TestUserDetails(USERNAME);
}
}
static class TestUserDetails implements UserDetails {
private static final long serialVersionUID = -6779736987183888865L;
private String username;
TestUserDetails(String username) {
this.username = username;
}
@Override
public String getUsername() {
return username;
}
...
}
}
What happens here is that the test keeps failing because when the UserDetails is actually loaded the USERNAME variable is still null.
Expected Behavior
I would expect the @BeforeEach method to be executed before the SecurityContext initialization therefore allowing the creation of a UserDetails with a non null username.
Configuration
Version
I am using Spring Boot Dependency 2.1.3.RELEASE (=> Spring Security Test 5.1.4.RELEASE).
Sample
Comment From: jfriedenstab
I stumbled upon this issue, too. I would like to create a custom UserDetails object in the @BeforeEach method which can then be used by @WithUserDetails.
Are there any plans to provide a fix for this?
Comment From: piotr-karon
For anyone with this problem, as this is still not resolved.
Instead of saving user to repository in @Before or @BeforeEach create separate method annotated with @PostConstruct and save user. Assuming you have correctly implemented custom UserDetailsService and @SpringBootTest picks it (or you provide bean name in @WithUserDetails)
private const val USERNAME = "username"
private val user = User(USERNAME)
@SpringBootTest
@WithUserDetails(USERNAME)
class TestClass @Autowired constructor(
private val userRepo: UserRepository
){
@PostConstruct
fun saveUser(){
userRepo.save(user)
}
@Test
fun someTest(){
<user is available here>
}
}
Comment From: sambernet
Not specific to JUnit 5, same problem also affects vintage JUnit4 tests.
But looking at the brand new PR this was a general issue with the WithUserDetails and both should be fixed with this change. 🥳
Thanks 👍
Comment From: rwinch
This is now fixed via gh-6591 Closing as duplicate of the PR