Spring-Boot WebMvcTest:如何使用身份验证对象参数测试控制器方法? [英] Spring-Boot WebMvcTest: How to test controller method with Authentication object parameter?
问题描述
这是这个问题的延续Spring WebMvcTest 如何模拟身份验证?
我正在尝试在 Spring-boot 中测试一个控制器方法,该方法接收一个 Authentication
对象作为参数.控制器是一个带有 @CrossOrigin
注释的 RestController
.该方法如下所示:
I'm trying to test a controller method in Spring-boot that receives an Authentication
object as parameter. The controller is a RestController
with @CrossOrigin
annotation. The method looks like this:
@GetMapping("/authentication")
public String testAuthentication(Authentication authentication) {
UserDetailsStub userDetailsStub = (UserDetailsStub) authentication.getPrincipal();
return userDetailsStub.getUsername();
}
如您所见,我从 Authentication 参数中获取了主体.
As you can see i get the principal from the Authentication out of the parameters.
问题是,在我的 WebMvcTest
测试用例中,我得到一个 NullPointerException
,因为在测试用例中,authentication
似乎为空.我的问题是为什么?
The problem is, in my WebMvcTest
test case i get a NullPointerException
because in the test case, authentication
seems to be null. My question is why?
我尝试添加一个 given
调用,该调用将在测试用例中的 @PostConstruct
注释方法中返回一个自定义的 UserDetails
对象,但是我仍然得到 NullPointerException
.
I have tried adding a given
call which will return a custom UserDetails
object in a @PostConstruct
annotated metho in the test case, but still i get the NullPointerException
.
我的测试用例如下所示:
My test case looks like this:
@Import(SecurityConfiguration.class)
@RunWith(SpringRunner.class)
@WebMvcTest(PDPController.class)
@AutoConfigureMockMvc(addFilters = false)
public class PDPControllerTests {
@Autowired
private MockMvc mvc;
@MockBean(name = "userDetailsService")
private MyUserDetailsService userDetailsService;
//..
@PostConstruct
public void setup() {
given(userDetailsService.loadUserByUsername(anyString()))
.willReturn(new UserDetailsStub());
}
//..
@Test
@WithUserDetails(value = "username", userDetailsServiceBeanName = "userDetailsService")
public void testAuthentication() throws Exception {
mvc.perform(get("/pdps/authentication").secure(true)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
为什么在测试用例中 authentication
为 null,即使我在 @PostConstruct
方法中提供它?
Why is authentication
null in the test case, even when i supply it in the @PostConstruct
method?
可以在此处找到重现错误的代码最少的 GitHub 项目.https://github.com/Kars1090/SpringSecurityTest
A GitHub project with minimal code that reproduces the error can be found here. https://github.com/Kars1090/SpringSecurityTest
谢谢!
推荐答案
克隆您的项目后,我已实现在您的控制器方法中接收有效的 Authentication
对象.基本上,您在测试中有两个主要问题:
After clone your project I have achieved to receive a valid Authentication
object in your controller method. Basically you have 2 main problems in your test:
- 不必要的额外配置
- 过滤器的错误模拟配置:
JwtRequestFilter
总的来说,变化如下:
public class UserDetailsStub implements UserDetails {
private String username;
private String password;
private Collection<? extends GrantedAuthority> authorities;
public UserDetailsStub() {}
public static UserDetailsStub of (User user) {
UserDetailsStub userDetails = new UserDetailsStub();
if (null != user) {
userDetails.username = user.getUsername();
userDetails.password = user.getPassword();
userDetails.authorities = user.getAuthorities();
}
return userDetails;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
// Rest of the code is equal to your version
您的控制器方法:
@GetMapping("/authentication")
public String testAuthentication(Authentication authentication) {
UserDetailsStub userDetailsStub = UserDetailsStub.of((User)
authentication.getPrincipal());
return userDetailsStub.getUsername();
}
和测试:
@WebMvcTest(value = PDPController.class)
public class PDPControllerTests {
@Autowired
private MockMvc mvc;
/** You have not to mock the filter because in that case Spring
* won't know how to deal with it, when the list of them
* should be managed.
*
* That is the reason why you had to include
* @AutoConfigureMockMvc(addFilters = false), but that
* is preciselly what was avoiding the creation of your
* Authentication object, because your JwtRequestFilter
* was not being executed.
*
* With the current code, your filter will be executed and
* the Authentication object created.
*/
//@MockBean
//private JwtRequestFilter jwtRequestFilter;
// What you have to mock are the classes the filter uses internally
@MockBean
private MyUserDetailsService userDetailsService;
@MockBean
private JwtService jwtService;
@Test
@WithMockUser
public void test() throws Exception {
mvc.perform(
get("/pdps/authentication").secure(true)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
这篇关于Spring-Boot WebMvcTest:如何使用身份验证对象参数测试控制器方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!