and*_*ucz 17 java spring spring-mvc spring-security spring-test
我在尝试测试一个接收an UserDetails作为参数注释的休息端点时遇到了麻烦@AuthenticationPrincipal.
似乎没有使用在测试场景中创建的用户实例,但是尝试使用默认构造函数进行实例化: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.andrucz.app.AppUserDetails]: No default constructor found;
REST端点:
@RestController
@RequestMapping("/api/items")
class ItemEndpoint {
@Autowired
private ItemService itemService;
@RequestMapping(path = "/{id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Callable<ItemDto> getItemById(@PathVariable("id") String id, @AuthenticationPrincipal AppUserDetails userDetails) {
return () -> {
Item item = itemService.getItemById(id).orElseThrow(() -> new ResourceNotFoundException(id));
...
};
}
}
Run Code Online (Sandbox Code Playgroud)
测试类:
public class ItemEndpointTests {
@InjectMocks
private ItemEndpoint itemEndpoint;
@Mock
private ItemService itemService;
private MockMvc mockMvc;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(itemEndpoint)
.build();
}
@Test
public void findItem() throws Exception {
when(itemService.getItemById("1")).thenReturn(Optional.of(new Item()));
mockMvc.perform(get("/api/items/1").with(user(new AppUserDetails(new User()))))
.andExpect(status().isOk());
}
}
Run Code Online (Sandbox Code Playgroud)
如何在不必切换的情况下解决该问题webAppContextSetup?我想编写完全控制服务模拟的测试,所以我正在使用standaloneSetup.
这可以通过将a HandlerMethodArgumentResolver注入到Mock MVC上下文或独立设置中来完成.假设你@AuthenticationPrincipal的类型是ParticipantDetails:
private HandlerMethodArgumentResolver putAuthenticationPrincipal = new HandlerMethodArgumentResolver() {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().isAssignableFrom(ParticipantDetails.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return new ParticipantDetails(…);
}
};
Run Code Online (Sandbox Code Playgroud)
这个参数解析器可以处理类型ParticipantDetails并且只是凭空创建它,但是你会看到你获得了大量的上下文.稍后,这个参数解析器附加到模拟MVC对象:
@BeforeMethod
public void beforeMethod() {
mockMvc = MockMvcBuilders
.standaloneSetup(…)
.setCustomArgumentResolvers(putAuthenticationPrincipal)
.build();
}
Run Code Online (Sandbox Code Playgroud)
这将导致您的带@AuthenticationPrincipal注释的方法参数填充解析器中的详细信息.
我知道这个问题已经很老了,但对于仍在寻找的人来说,对我来说编写 Spring Boot 测试有用@AuthenticationPrincipal(这可能不适用于所有实例)的是注释测试@WithMockUser("testuser1")
@Test
@WithMockUser("testuser1")
public void successfullyMockUser throws Exception {
mvc.perform(...));
}
Run Code Online (Sandbox Code Playgroud)
这是Spring 文档的链接@WithMockUser
出于某种原因,Michael Piefel 的解决方案对我不起作用,所以我想出了另一个。
首先,创建抽象配置类:
@RunWith(SpringRunner.class)
@SpringBootTest
@TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
WithSecurityContextTestExecutionListener.class})
public abstract MockMvcTestPrototype {
@Autowired
protected WebApplicationContext context;
protected MockMvc mockMvc;
protected org.springframework.security.core.userdetails.User loggedUser;
@Before
public voivd setUp() {
mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
loggedUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以写这样的测试:
public class SomeTestClass extends MockMvcTestPrototype {
@Test
@WithUserDetails("someUser@app.com")
public void someTest() throws Exception {
mockMvc.
perform(get("/api/someService")
.withUser(user(loggedUser)))
.andExpect(status().isOk());
}
}
Run Code Online (Sandbox Code Playgroud)
并且@AuthenticationPrincipal 应该将您自己的 User 类实现注入到控制器方法中
public class SomeController {
...
@RequestMapping(method = POST, value = "/update")
public String update(UdateDto dto, @AuthenticationPrincipal CurrentUser user) {
...
user.getUser(); // works like a charm!
...
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8626 次 |
| 最近记录: |