반응형
🚨오류
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

https://velog.io/@tjdtn0219/SpringSecurity%EC%A0%81%EC%9A%A9-%ED%9B%84-Controller-%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%BD%94%EB%93%9C-%EC%9E%91%EC%84%B1-%EC%8B%9C-%EB%B0%9C%EC%83%9D%ED%96%88%EB%8D%98-%EC%98%A4%EB%A5%98%EB%93%A4-Feat.-Junit5-csrf

 

[Spring]Security적용 후 Controller 테스트코드 작성 시 발생했던 오류들 (Feat. Junit5, csrf)

Controller에서 모든 Board를 조회하는 메소드를 테스트 코드를 작성하던 중 일어난 일이다. 우선 코드를 먼저보자 사실 이 로직상은 아무 문제가 없다.하지만 다음과 같이 401 Unauthorized가 발생하는

velog.io

 

 

 

반응형

*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*