🚨오류
java.lang.AssertionError: Status expected:<201> but was:<401>
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:61)
at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:128)
at org.springframework.test.web.servlet.result.StatusResultMatchers.lambda$matcher$9(StatusResultMatchers.java:640)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:214)
at com.mini_prioject.display_board.controller.UserControllerTest.createUserSuccessTest(UserControllerTest.java:77)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
✍️원인
By default, tests annotated with @WebMvcTest will also auto-configure Spring Security
@WebMvcTest 사용 시, 스프링 시큐리티가 자동으로 구성하는 Configuration 파일들을 불러와서 사용
자동으로 구성되는 SpringBootWebSecurityConfiguration이 권한을 요청하지만 인증 권한을 가진 사용자로 테스트하지 않아 오류 발생
@Configuration(proxyBeanMethods = false)
@ConditionalOnDefaultWebSecurity
@ConditionalOnWebApplication(type = Type.SERVLET)
class SpringBootWebSecurityConfiguration {
@Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic();
return http.build();
}
}
@SpringBootTest
통합 테스트에서 주로 사용
애플리케이션의 모든 컴포넌트들을 로드
실제 애플리케이션 환경과 유사한 환경에서 테스트
@WebMvcTest
주로 웹 계층만 테스트할 때 사용(컨트롤러 단위 테스트)
주로 컨트롤러(Controller)와 관련된 빈들만 로드하므로, 더 가벼우며 빠른 테스트가 가능(securityConfig 로드 x)
✅해결
인증 권한을 가진 User 생성( @WithMockUser )
@WithMockUser(username = "testUser", roles = "USER")
@WebMvcTest(UserController.class)
class UserControllerTest { }
실제 DB에서 가져온 사용자 정보로 테스트 수행(@WithUserDetails)
// 테스트 User를 반환하는 로직
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return User.builder()
.username("testUser")
.password(new BCryptPasswordEncoder().encode("password123"))
.roles("USER")
.build();
}
}
// 실제 DB에 저장된 User를 반환하는 로직
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepository.findByUsername(username)
.map(user -> User.builder()
.username(user.getUsername())
.password(user.getPassword())
.roles(user.getRole())
.build())
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
}
}
@WebMvcTest(UserController.class)
@Import(SecurityConfig.class)
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
@DisplayName("Principal 내부 값 테스트")
@WithUserDetails(value = "testUser")
void testWithUserDetails() throws Exception {
mockMvc.perform(get("/api/v1/profile"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.username").value("testUser"));
}
}
@WithMockUser - 인증된 사용자
@WithAnonymousUser - 미인증 사용자 (principal에서 "anonymous"가 들어가있음)
@WithUserDetails - 메서드가 principal 내부의 값을 직접 사용하는 경우 (별도의 사전 설정 필요)
- WithUserDetails를 사용하면 UserDetailsService가 동작해서 Principal을 설정해줌
- loadUserByUsername()이 직접 UserDetails를 반환
📚참고
https://suhyeon-developer.tistory.com/38
[SpringBoot] Controller Unit Test에서 발생한 401, 403 에러를 해결해보자! (+ Spring Security)
❗️컨트롤러 테스트코드를 작성하는 와중에 401과 403 에러를 마주쳤다. 해결하는건 크게 어렵지 않았다!!! 컨트롤러 단위 테스트 진행 과정 먼저, 사용한 기술은 이러하다. ▶︎ Spring Data JPA , Spr
suhyeon-developer.tistory.com
[Spring]Security적용 후 Controller 테스트코드 작성 시 발생했던 오류들 (Feat. Junit5, csrf)
Controller에서 모든 Board를 조회하는 메소드를 테스트 코드를 작성하던 중 일어난 일이다. 우선 코드를 먼저보자 사실 이 로직상은 아무 문제가 없다.하지만 다음과 같이 401 Unauthorized가 발생하는
velog.io
'Java > Java with Error' 카테고리의 다른 글
java.lang.AssertionError: No value at JSON path "$.userId" (0) | 2025.03.29 |
---|---|
java.lang.AssertionError: Status expected:<201> but was:<403> (0) | 2025.03.29 |
[해결 방법] no suitable constructor found for Jackson2JsonRedisSerializer(Class<CAP#1>) (0) | 2024.11.24 |
[해결 방법] error: no suitable method found for ... (0) | 2023.10.17 |
[해결 방법] java.lang.ClassCastException (0) | 2023.08.15 |