문제 상황

톰캣을 실행하고 나서 아래 메서드에 접근하게 되면 Member 객체에 실제로 DB에 저장된 member 정보를 받아온다.

그런데 만약 위 메서드를 아래의 테스트 코드로 실행할 때에는 @AuthenticationPrincipal의 Member를 null로 받아와서 컨트롤러 테스트가 진행이 안된다.

문제 파악

에러 해석:

given으로 userEmail이라는 지정 문자열(여기선 “[email protected]”)이 들어오면 이에 대한 결과값을 반환하는 코드를 작성하였는데, 실제 테스트를 하면 null 값이 반환되어 테스트가 실패한다.

에러 원인:

@AuthenticationPrincipal로 받아오는 Member자체가 null이라서 member.getEmail() 메서드가 성립이되지 않는다.

에러 분석:

@AuthenticationPrincipal의 Member 정보는 어느 시점에 주입되는가? 테스트 코드에 작성한 컨트롤러 메서드 호출로는 주입이 안되는 것인가?

@AuthenticationPrincipalMember 정보가 주입되는 시점은 Spring Security 필터 체인에서 인증이 완료된 후이다. Spring Security는 필터 체인을 통해 인증이 성공한 유저에 한해 SecurityContextAuthentication 객체를 설정한다.

✔️ 이 Authentication 객체는 Principal을 포함하며, @AuthenticationPrincipal을 통해 Principal을 주입할 수 있게 된다.

⇒ 즉, 우리는 단위 테스트 중이라서, 필터 체인과 SecurityContext 설정 과정이 생략되어 Member 객체가 null로 설정되는 것이다.

문제 해결

통합 테스트로 이끌 경우,

SecurityContext를 직접 설정해줘야 한다.

방법1. SecurityContext에 Authentication 객체를 수동으로 설정한다.

방법2. Spring Security Test 라이브러리를 사용한다.

@WithMockUser 또는 @WithUserDetails와 같은 어노테이션을 이용하여 인증된 사용자를 쉽게 설정할 수 있다.

단위 테스트로 이끌 경우,