I have a controller with the following method. I get the Authentication
from the method parameters and use it to get the principal.
@PatchMapping("/{employeeId}/present")
public PersonalDevelopmentPlan savePresent(@PathVariable int employeeId,
@RequestBody PersonalDevelopmentPlan personalDevelopmentPlan,
Authentication authentication) {
EmployeeDetails details = (EmployeeDetails) authentication.getPrincipal();
return pdpService.savePresent(employeeId, personalDevelopmentPlan, details.getEmployee().getId());
}
I then have this test case using @WebMvcTest
@Test
@WithMockUser
public void testSavePresent_returns_result_from_service() throws Exception {
PersonalDevelopmentPlan pdp = new PersonalDevelopmentPlan();
pdp.setEmployee(EMPLOYEE_ID);
given(service.savePresent(eq(EMPLOYEE_ID), any(), anyInt())).willReturn(pdp);
mvc.perform(patch(URL_WITH_ID + "/present").secure(true)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(pdp)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.employee", Matchers.is(EMPLOYEE_ID)));
}
When i run this though, i get a NullPointerException
on the following line:
EmployeeDetails details = (EmployeeDetails) authentication.getPrincipal();
Because authentication is null. I already annotated the test with @MockUser
but still authentication is null. How do i mock authentication in the parameters of the controller method?
My test is annotated with @AutoConfigureMockMvc(addFilters = false)
Thanks!
@WithMockUser
This will use the principal on the Authentication is Spring Security’s User object
While @WithMockUser
is a very convenient way to get started, it may not work in all instances. For example, it is common for applications to expect that the Authentication
principal be of a specific type. This is done so that the application can refer to the principal as the custom type and reduce coupling on Spring Security.
The custom principal is often times returned by a custom UserDetailsService
that returns an object that implements both UserDetails
and the custom type. For situations like this, it is useful to create the test user using the custom UserDetailsService. That is exactly what @WithUserDetails
does.
We can create our own annotation that uses the @WithSecurityContext to create any SecurityContext we want. For example, we might create an annotation named @WithMockCustomUser as @WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class)