![](/img/trans.png)
[英]How to exclude a @Configuration class when using @WebMvcTest with spring-boot?
[英]Spring-Boot WebMvcTest: How to test controller method with Authentication object parameter?
這是這個問題Spring WebMvcTest 如何模擬身份驗證的延續?
我正在嘗試在 Spring-boot 中測試 controller 方法,該方法接收Authentication
object 作為參數。 controller 是一個帶有RestController
注釋的@CrossOrigin
。 該方法如下所示:
@GetMapping("/authentication")
public String testAuthentication(Authentication authentication) {
UserDetailsStub userDetailsStub = (UserDetailsStub) authentication.getPrincipal();
return userDetailsStub.getUsername();
}
如您所見,我從參數中獲取了身份驗證的主體。
問題是,在我的WebMvcTest
測試用例中,我得到了NullPointerException
,因為在測試用例中, authentication
似乎是 null。 我的問題是為什么?
我嘗試添加一個given
的調用,該調用將在測試用例的@PostConstruct
注釋方法中返回自定義UserDetails
object ,但我仍然得到NullPointerException
。
我的測試用例如下所示:
@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
方法中提供它?
可以在此處找到具有重現錯誤的最少代碼的 GitHub 項目。 https://github.com/Kars1090/SpringSecurityTest
謝謝!
克隆您的項目后,我已經在您的 controller 方法中獲得了有效的Authentication
object。 基本上,您的測試中有兩個主要問題:
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
您的 controller 方法:
@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());
}
}
一個(不好的)解決方法是從 controller 參數中刪除authentication
,而是通過SecurityContextHolder.getContext().getAuthentication()
獲取身份驗證。
這將使測試工作而無需更改任何其他內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.