【发布时间】:2020-04-29 11:29:30
【问题描述】:
在下面的测试类中,我不希望 @EnableWebSecurity 注解的类被 Spring Context 捕获:
@WebMvcTest(controllers = UserController.class)
class UserControllerTest {
@MockBean
private UserService userService;
@Autowired
private ObjectMapper jsonMapper;
@Autowired
private MockMvc mockMvc;
@Test
void create_should_return_registered_user_when_request_is_valid() throws Exception {
// given
final String EMAIL = "test@test.com";
final String PASSWORD = "test_password";
final UserDto userDto = buildDto(EMAIL, PASSWORD);
final User expectedUser = buildUser(EMAIL, PASSWORD);
// when
when(userService.registerUser(userDto)).thenReturn(expectedUser);
// then
MvcResult response = mockMvc.perform(post(UserAPI.BASE_URL)
.contentType(MediaType.APPLICATION_JSON)
.content(jsonMapper.writeValueAsString(userDto)))
.andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
String responseBodyJson = response.getResponse().getContentAsString();
User responseUser = jsonMapper.readValue(responseBodyJson, User.class);
assertThat(responseUser, is(equalTo(expectedUser)));
verify(userService, times(1)).registerUser(userDto);
verifyNoMoreInteractions(userService);
}
@Test
void create_should_return_conflict_when_request_valid_but_email_in_use() throws Exception {
// given
final String EMAIL = "test@test.com";
final String PASSWORD = "test_password";
final UserDto userDto = buildDto(EMAIL, PASSWORD);
// when
when(userService.registerUser(userDto)).thenThrow(new EmailAlreadyInUseException(EMAIL));
// then
mockMvc.perform(post(UserAPI.BASE_URL)
.contentType(MediaType.APPLICATION_JSON)
.content(jsonMapper.writeValueAsString(userDto)))
.andExpect(status().isConflict());
verify(userService, times(1)).registerUser(userDto);
verifyNoMoreInteractions(userService);
}
@Test
void create_should_return_bad_request_when_request_has_invalid_email() throws Exception {
// given
final String BAD_EMAIL = "test_test.com";
final String PASSWORD = "test_password";
final UserDto userDto = buildDto(BAD_EMAIL, PASSWORD);
// when
// then
mockMvc.perform(post(UserAPI.BASE_URL)
.contentType(MediaType.APPLICATION_JSON)
.content(jsonMapper.writeValueAsString(userDto)))
.andExpect(status().isBadRequest());
verifyNoInteractions(userService);
}
@Test
void create_should_return_bad_request_when_request_has_invalid_password() throws Exception {
// given
final String EMAIL = "test@test.com";
final String BAD_PASSWORD = "";
final UserDto userDto = buildDto(EMAIL, BAD_PASSWORD);
// when
// then
mockMvc.perform(post(UserAPI.BASE_URL)
.contentType(MediaType.APPLICATION_JSON)
.content(jsonMapper.writeValueAsString(userDto)))
.andExpect(status().isBadRequest());
verifyNoInteractions(userService);
}
@Test
void create_should_return_bad_request_when_request_is_missing_email() throws Exception {
// given
final String PASSWORD = "test_password";
final UserDto userDto = buildDto(null, PASSWORD);
// when
// then
mockMvc.perform(post(UserAPI.BASE_URL)
.contentType(MediaType.APPLICATION_JSON)
.content(jsonMapper.writeValueAsString(userDto)))
.andExpect(status().isBadRequest());
verifyNoInteractions(userService);
}
@Test
void create_should_return_bad_request_when_request_is_missing_password() throws Exception {
// given
final String EMAIL = "test@test.com";
final UserDto userDto = buildDto(EMAIL, null);
// when
// then
mockMvc.perform(post(UserAPI.BASE_URL)
.contentType(MediaType.APPLICATION_JSON)
.content(jsonMapper.writeValueAsString(userDto)))
.andExpect(status().isBadRequest());
verifyNoInteractions(userService);
}
private UserDto buildDto(String email, String password) {
UserDto userDto = new UserDto();
userDto.setEmail(email);
userDto.setPassword(password);
return userDto;
}
private User buildUser(String email, String password){
User user = new User();
user.setId(1);
user.setEmail(email);
user.setPassword(password);
return user;
}
}
现在默认加载,因为它的依赖没有加载,所以报错:
com.example.ordersapi.auth.configuration.SecurityConfiguration 中构造函数的参数 0 需要一个无法找到的 'org.springframework.security.core.userdetails.UserDetailsService' 类型的 bean。
我见过一些解决方案,例如 @WebMvcTest(controllers = SomeController.class, secure = false),但这些似乎已被弃用。
我正在运行 Spring Boot v2.2.2.RELEASE。
这是安全配置类:
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Value("${spring.h2.console.enabled:false}")
private boolean h2ConsoleEnabled;
private final UserDetailsService userDetailsService;
private final AuthorizationFilter authorizationFilter;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
if (h2ConsoleEnabled) {
http.authorizeRequests()
.antMatchers("/h2-console", "/h2-console/**").permitAll()
.and()
.headers().frameOptions().sameOrigin();
}
http.cors().and().csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler())
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, AuthenticationAPI.BASE_URL).permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authorizationFilter, UsernamePasswordAuthenticationFilter.class);
}
private AuthenticationEntryPoint unauthorizedHandler() {
return (request, response, e) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
/**
* We have to create this bean otherwise we can't wire AuthenticationManager in our code.
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
【问题讨论】:
-
你能分享你的 com.example.ordersapi.auth.configuration.SecurityConfiguration 吗?谢谢
-
已添加到问题中。谢谢!
-
您是否创建了自己的
UserDetailsService实现?如果有,请提供。你很接近,没有错过太多。 -
嗨,我确实尝试过提供它,它也是依赖项,但之后我遇到了另一个问题:spring security is up,显然没有使用我的配置/服务,即使它们被加载到上下文,当我尝试使用 @WithMockService 时,我仍然得到 403 Forbidden 作为响应状态
-
它应该是……奇怪。请分享它,以便我可以尝试复制...谢谢
标签: java spring spring-boot spring-security spring-test