我有一个具有以下方法的控制器。我从方法参数中获取Authentication
并使用它来获取主体。
@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());
}
然后,我使用@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)));
}
但是,当我运行它时,我在以下行得到一个NullPointerException
:
EmployeeDetails details = (EmployeeDetails) authentication.getPrincipal();
因为身份验证为空。我已经用@MockUser
注释了测试,但身份验证仍然为空。如何在控制器方法的参数中模拟身份验证?
我的测试带有注释@AutoConfigureMockMvc(addFilters = false)
谢谢!
@WithMockUser
这将使用身份验证上的主体是 Spring Security 的用户对象
@WithUserDetails
虽然@WithMockUser
是一种非常方便的入门方法,但它可能并非在所有情况下都有效。例如,应用程序通常期望Authentication
主体是特定类型。这样做是为了使应用程序可以将主体称为自定义类型,并减少 Spring 安全性上的耦合。
自定义主体通常由自定义UserDetailsService
返回,该返回同时实现UserDetails
和自定义类型的对象。对于此类情况,使用自定义用户详细信息服务创建测试用户非常有用。这正是@WithUserDetails
所做的。
@WithSecurityContext
我们可以创建自己的注释,使用该注释@WithSecurityContext来创建我们想要的任何SecurityContext。例如,我们可以创建一个名为 @WithMockCustomUser 的注释作为@WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class)
如果最初在数据库中保留了用户(或者在 @PostConstruct 中创建用户),则可以使用 @WithUserDetails 注释。