77import com .back .domain .user .entity .UserStatus ;
88import com .back .domain .user .repository .UserProfileRepository ;
99import com .back .domain .user .repository .UserRepository ;
10+ import com .back .domain .user .repository .UserTokenRepository ;
1011import com .back .global .exception .CustomException ;
1112import com .back .global .exception .ErrorCode ;
1213import jakarta .servlet .http .Cookie ;
1314import org .junit .jupiter .api .DisplayName ;
1415import org .junit .jupiter .api .Test ;
1516import org .springframework .beans .factory .annotation .Autowired ;
1617import org .springframework .boot .test .context .SpringBootTest ;
18+ import org .springframework .mock .web .MockHttpServletRequest ;
1719import org .springframework .mock .web .MockHttpServletResponse ;
1820import org .springframework .security .crypto .password .PasswordEncoder ;
1921import org .springframework .test .context .ActiveProfiles ;
@@ -36,6 +38,9 @@ class UserServiceTest {
3638 @ Autowired
3739 private UserProfileRepository userProfileRepository ;
3840
41+ @ Autowired
42+ private UserTokenRepository userTokenRepository ;
43+
3944 @ Autowired
4045 private PasswordEncoder passwordEncoder ;
4146
@@ -263,4 +268,59 @@ void login_deletedUser() {
263268 .isInstanceOf (CustomException .class )
264269 .hasMessage (ErrorCode .USER_DELETED .getMessage ());
265270 }
271+ @ Test
272+ @ DisplayName ("정상 로그아웃 성공 → RefreshToken DB 삭제 + 쿠키 만료" )
273+ void logout_success () {
274+ // given: 정상 로그인된 사용자
275+ String rawPassword = "P@ssw0rd!" ;
276+ User user =
setupUser (
"logoutuser" ,
"[email protected] " ,
rawPassword ,
"닉네임" ,
UserStatus .
ACTIVE );
277+ MockHttpServletResponse loginResponse = new MockHttpServletResponse ();
278+
279+ userService .login (new LoginRequest ("logoutuser" , rawPassword ), loginResponse );
280+ Cookie refreshCookie = loginResponse .getCookie ("refreshToken" );
281+ assertThat (refreshCookie ).isNotNull ();
282+
283+ MockHttpServletResponse logoutResponse = new MockHttpServletResponse ();
284+ MockHttpServletRequest request = new MockHttpServletRequest ();
285+ request .setCookies (refreshCookie ); // 쿠키를 요청에 실어줌
286+
287+ // when: 로그아웃 실행
288+ userService .logout (request , logoutResponse );
289+
290+ // then: DB에서 refreshToken 삭제됨
291+ assertThat (userTokenRepository .findByRefreshToken (refreshCookie .getValue ())).isEmpty ();
292+
293+ // 응답 쿠키는 만료 처리됨
294+ Cookie cleared = logoutResponse .getCookie ("refreshToken" );
295+ assertThat (cleared ).isNotNull ();
296+ assertThat (cleared .getMaxAge ()).isZero ();
297+ assertThat (cleared .getValue ()).isNull ();
298+ }
299+
300+ @ Test
301+ @ DisplayName ("RefreshToken 없으면 INVALID_TOKEN 예외 발생" )
302+ void logout_noToken () {
303+ // given: 쿠키 없이 로그아웃 요청
304+ MockHttpServletRequest request = new MockHttpServletRequest ();
305+ MockHttpServletResponse response = new MockHttpServletResponse ();
306+
307+ // when & then
308+ assertThatThrownBy (() -> userService .logout (request , response ))
309+ .isInstanceOf (CustomException .class )
310+ .hasMessage (ErrorCode .BAD_REQUEST .getMessage ());
311+ }
312+
313+ @ Test
314+ @ DisplayName ("유효하지 않은 RefreshToken이면 INVALID_TOKEN 예외 발생" )
315+ void logout_invalidToken () {
316+ // given: 잘못된 토큰 쿠키 세팅
317+ MockHttpServletRequest request = new MockHttpServletRequest ();
318+ request .setCookies (new Cookie ("refreshToken" , "invalidToken" ));
319+ MockHttpServletResponse response = new MockHttpServletResponse ();
320+
321+ // when & then
322+ assertThatThrownBy (() -> userService .logout (request , response ))
323+ .isInstanceOf (CustomException .class )
324+ .hasMessage (ErrorCode .INVALID_TOKEN .getMessage ());
325+ }
266326}
0 commit comments