В следующем тестовом классе я не хочу, чтобы аннотированный класс @EnableWebSecurity был перехвачен контекстом Spring:
@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;
}
}
Сейчас он загружается по умолчанию и, поскольку его зависимости не загружается, выдает ошибку:
Параметру 0 конструктора в com.example.ordersapi.auth.configuration.SecurityConfiguration требуется bean-компонент типа 'org.springframework.security.core.userdetails.UserDetailsService 'это не может быть найдено.
Я видел некоторые решения, такие как @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();
}
}