From ba01b3c245aae99dabd5ae91bdb744c108bf0c4d Mon Sep 17 00:00:00 2001
From: minyul <ggomjae@gmail.com>
Date: Wed, 23 Feb 2022 12:12:21 +0900
Subject: [PATCH 01/10] =?UTF-8?q?refactor=20:=20ObjectMapper=20=EC=88=98?=
 =?UTF-8?q?=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/main/java/nextstep/auth/AuthConfig.java              | 4 ++--
 .../subway/unit/TokenAuthenticationInterceptorTest.java  | 9 ++++++---
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/src/main/java/nextstep/auth/AuthConfig.java b/src/main/java/nextstep/auth/AuthConfig.java
index db64b8fb1..63327732f 100644
--- a/src/main/java/nextstep/auth/AuthConfig.java
+++ b/src/main/java/nextstep/auth/AuthConfig.java
@@ -22,10 +22,10 @@ public class AuthConfig implements WebMvcConfigurer {
     private ObjectMapper objectMapper;
     private Authorizor authorizor;
 
-    public AuthConfig(UserDetailsService userDetailsService, JwtTokenProvider jwtTokenProvider) {
+    public AuthConfig(UserDetailsService userDetailsService, JwtTokenProvider jwtTokenProvider, ObjectMapper objectMapper) {
         this.userDetailsService = userDetailsService;
         this.jwtTokenProvider = jwtTokenProvider;
-        this.objectMapper = new ObjectMapper();
+        this.objectMapper = objectMapper;
         this.authorizor = new Authorizor();
     }
 
diff --git a/src/test/java/nextstep/subway/unit/TokenAuthenticationInterceptorTest.java b/src/test/java/nextstep/subway/unit/TokenAuthenticationInterceptorTest.java
index 39f655ade..719f4157e 100644
--- a/src/test/java/nextstep/subway/unit/TokenAuthenticationInterceptorTest.java
+++ b/src/test/java/nextstep/subway/unit/TokenAuthenticationInterceptorTest.java
@@ -2,6 +2,7 @@
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import nextstep.auth.authentication.AuthenticationToken;
+import nextstep.auth.authentication.Authorizor;
 import nextstep.auth.authentication.TokenAuthenticationInterceptor;
 import nextstep.auth.context.Authentication;
 import nextstep.auth.token.JwtTokenProvider;
@@ -34,6 +35,7 @@ class TokenAuthenticationInterceptorTest {
     public static final String JWT_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjJ9.ih1aovtQShabQ7l0cINw4k1fagApg3qLWiB8Kt59Lno";
 
     private ObjectMapper objectMapper;
+    private Authorizor authorizor;
 
     @Mock
     private CustomUserDetailsService userDetailsService;
@@ -44,12 +46,13 @@ class TokenAuthenticationInterceptorTest {
     @BeforeEach
     void init() {
         objectMapper = new ObjectMapper();
+        authorizor = new Authorizor();
     }
 
     @Test
     void convert() throws IOException {
         // given
-        TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(userDetailsService, jwtTokenProvider, objectMapper);
+        TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(userDetailsService, jwtTokenProvider, objectMapper, authorizor);
         MockHttpServletRequest request = createMockRequest();
 
         // when
@@ -62,7 +65,7 @@ void convert() throws IOException {
 
     @Test
     void authenticate() {
-        TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(userDetailsService, jwtTokenProvider, objectMapper);
+        TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(userDetailsService, jwtTokenProvider, objectMapper, authorizor);
 
         when(userDetailsService.loadUserByUsername(EMAIL)).thenReturn(new LoginMember(1L, EMAIL, PASSWORD, 20));
 
@@ -74,7 +77,7 @@ void authenticate() {
 
     @Test
     void preHandle() throws IOException, JSONException {
-        TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(userDetailsService, jwtTokenProvider, objectMapper);
+        TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(userDetailsService, jwtTokenProvider, objectMapper, authorizor);
 
         when(userDetailsService.loadUserByUsername(EMAIL)).thenReturn(new LoginMember(1L, EMAIL, PASSWORD, 20));
         when(jwtTokenProvider.createToken(anyString())).thenReturn(JWT_TOKEN);

From bc0773b1325cc02d80c8a12aee97fe929d2ed644 Mon Sep 17 00:00:00 2001
From: minyul <ggomjae@gmail.com>
Date: Wed, 23 Feb 2022 12:24:08 +0900
Subject: [PATCH 02/10] =?UTF-8?q?refactor=20:=20=EA=B3=B5=ED=86=B5?=
 =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=93=A4=EC=96=B4=EA=B0=80=EB=8A=94=20aut?=
 =?UTF-8?q?henticate=20=ED=95=A8=EC=88=98=EB=A5=BC=20=EB=A6=AC=ED=8C=A9?=
 =?UTF-8?q?=ED=86=A0=EB=A7=81=ED=95=98=EB=8B=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/main/java/nextstep/auth/AuthConfig.java   |  9 +++--
 .../auth/authentication/Authorizer.java       | 33 +++++++++++++++++++
 .../auth/authentication/Authorizor.java       | 17 ----------
 .../SessionAuthenticationInterceptor.java     | 17 +++-------
 .../TokenAuthenticationInterceptor.java       | 20 +++--------
 .../TokenAuthenticationInterceptorTest.java   | 14 ++++----
 6 files changed, 52 insertions(+), 58 deletions(-)
 create mode 100644 src/main/java/nextstep/auth/authentication/Authorizer.java
 delete mode 100644 src/main/java/nextstep/auth/authentication/Authorizor.java

diff --git a/src/main/java/nextstep/auth/AuthConfig.java b/src/main/java/nextstep/auth/AuthConfig.java
index 63327732f..e6e8f0cd2 100644
--- a/src/main/java/nextstep/auth/AuthConfig.java
+++ b/src/main/java/nextstep/auth/AuthConfig.java
@@ -1,14 +1,13 @@
 package nextstep.auth;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
-import nextstep.auth.authentication.Authorizor;
+import nextstep.auth.authentication.Authorizer;
 import nextstep.auth.authentication.SessionAuthenticationInterceptor;
 import nextstep.auth.authentication.TokenAuthenticationInterceptor;
 import nextstep.auth.authorization.AuthenticationPrincipalArgumentResolver;
 import nextstep.auth.authorization.SessionSecurityContextPersistenceInterceptor;
 import nextstep.auth.authorization.TokenSecurityContextPersistenceInterceptor;
 import nextstep.auth.token.JwtTokenProvider;
-import nextstep.member.application.CustomUserDetailsService;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@@ -20,19 +19,19 @@ public class AuthConfig implements WebMvcConfigurer {
     private UserDetailsService userDetailsService;
     private JwtTokenProvider jwtTokenProvider;
     private ObjectMapper objectMapper;
-    private Authorizor authorizor;
+    private Authorizer authorizor;
 
     public AuthConfig(UserDetailsService userDetailsService, JwtTokenProvider jwtTokenProvider, ObjectMapper objectMapper) {
         this.userDetailsService = userDetailsService;
         this.jwtTokenProvider = jwtTokenProvider;
         this.objectMapper = objectMapper;
-        this.authorizor = new Authorizor();
+        this.authorizor = new Authorizer(userDetailsService);
     }
 
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
         registry.addInterceptor(new SessionAuthenticationInterceptor(userDetailsService, authorizor)).addPathPatterns("/login/session");
-        registry.addInterceptor(new TokenAuthenticationInterceptor(userDetailsService, jwtTokenProvider, objectMapper, authorizor))
+        registry.addInterceptor(new TokenAuthenticationInterceptor(jwtTokenProvider, objectMapper, authorizor))
                 .addPathPatterns("/login/token");
         registry.addInterceptor(new SessionSecurityContextPersistenceInterceptor());
         registry.addInterceptor(new TokenSecurityContextPersistenceInterceptor(jwtTokenProvider));
diff --git a/src/main/java/nextstep/auth/authentication/Authorizer.java b/src/main/java/nextstep/auth/authentication/Authorizer.java
new file mode 100644
index 000000000..374259678
--- /dev/null
+++ b/src/main/java/nextstep/auth/authentication/Authorizer.java
@@ -0,0 +1,33 @@
+package nextstep.auth.authentication;
+
+import nextstep.auth.User;
+import nextstep.auth.UserDetailsService;
+import nextstep.auth.context.Authentication;
+import org.springframework.util.ObjectUtils;
+
+public class Authorizer {
+
+	private UserDetailsService userDetailsService;
+
+	public Authorizer(UserDetailsService userDetailsService) {
+		this.userDetailsService = userDetailsService;
+	}
+
+	public void checkAuthentication(User userDetails, AuthenticationToken token) {
+		if (ObjectUtils.isEmpty(userDetails)) {
+			throw new AuthenticationException();
+		}
+
+		if (!userDetails.checkPassword(token.getCredentials())) {
+			throw new AuthenticationException();
+		}
+	}
+
+	public Authentication authenticate(AuthenticationToken authenticationToken) {
+		final String principal = authenticationToken.getPrincipal();
+		final User userDetails = userDetailsService.loadUserByUsername(principal);
+		checkAuthentication(userDetails, authenticationToken);
+
+		return new Authentication(userDetails);
+	}
+}
diff --git a/src/main/java/nextstep/auth/authentication/Authorizor.java b/src/main/java/nextstep/auth/authentication/Authorizor.java
deleted file mode 100644
index 018c46d9a..000000000
--- a/src/main/java/nextstep/auth/authentication/Authorizor.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package nextstep.auth.authentication;
-
-import nextstep.auth.User;
-import org.springframework.util.ObjectUtils;
-
-public class Authorizor {
-
-	public void checkAuthentication(User userDetails, AuthenticationToken token) {
-		if (ObjectUtils.isEmpty(userDetails)) {
-			throw new AuthenticationException();
-		}
-
-		if (!userDetails.checkPassword(token.getCredentials())) {
-			throw new AuthenticationException();
-		}
-	}
-}
diff --git a/src/main/java/nextstep/auth/authentication/SessionAuthenticationInterceptor.java b/src/main/java/nextstep/auth/authentication/SessionAuthenticationInterceptor.java
index 610a16f54..10b1a7704 100644
--- a/src/main/java/nextstep/auth/authentication/SessionAuthenticationInterceptor.java
+++ b/src/main/java/nextstep/auth/authentication/SessionAuthenticationInterceptor.java
@@ -1,6 +1,5 @@
 package nextstep.auth.authentication;
 
-import nextstep.auth.User;
 import nextstep.auth.UserDetailsService;
 import nextstep.auth.context.Authentication;
 import nextstep.auth.context.SecurityContext;
@@ -20,17 +19,17 @@ public class SessionAuthenticationInterceptor implements HandlerInterceptor, Aut
     public static final String PASSWORD_FIELD = "password";
 
     private UserDetailsService userDetailsService;
-    private Authorizor authorizor;
+    private Authorizer authorizor;
 
-    public SessionAuthenticationInterceptor(UserDetailsService userDetailsService, Authorizor authorizor) {
+    public SessionAuthenticationInterceptor(UserDetailsService userDetailsService, Authorizer authorizor) {
         this.userDetailsService = userDetailsService;
         this.authorizor = authorizor;
     }
 
     @Override
-    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
         AuthenticationToken token = convert(request);
-        Authentication authentication = authenticate(token);
+        Authentication authentication = authorizor.authenticate(token);
 
         HttpSession httpSession = request.getSession();
         httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, new SecurityContext(authentication));
@@ -38,14 +37,6 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons
         return false;
     }
 
-    public Authentication authenticate(AuthenticationToken token) {
-        String principal = token.getPrincipal();
-        User userDetails = userDetailsService.loadUserByUsername(principal);
-        authorizor.checkAuthentication(userDetails, token);
-
-        return new Authentication(userDetails);
-    }
-
     @Override
     public AuthenticationToken convert(HttpServletRequest request) {
         Map<String, String[]> paramMap = request.getParameterMap();
diff --git a/src/main/java/nextstep/auth/authentication/TokenAuthenticationInterceptor.java b/src/main/java/nextstep/auth/authentication/TokenAuthenticationInterceptor.java
index 216cd21ca..e5881c1dd 100644
--- a/src/main/java/nextstep/auth/authentication/TokenAuthenticationInterceptor.java
+++ b/src/main/java/nextstep/auth/authentication/TokenAuthenticationInterceptor.java
@@ -1,7 +1,6 @@
 package nextstep.auth.authentication;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
-import nextstep.auth.User;
 import nextstep.auth.UserDetailsService;
 import nextstep.auth.context.Authentication;
 import nextstep.auth.token.JwtTokenProvider;
@@ -16,16 +15,13 @@
 
 public class TokenAuthenticationInterceptor implements HandlerInterceptor, AuthenticationConverter {
 
-    private UserDetailsService userDetailsService;
     private JwtTokenProvider jwtTokenProvider;
     private ObjectMapper objectMapper;
-    private Authorizor authorizor;
+    private Authorizer authorizor;
 
-    public TokenAuthenticationInterceptor(UserDetailsService userDetailsService,
-                                          JwtTokenProvider jwtTokenProvider,
+    public TokenAuthenticationInterceptor(JwtTokenProvider jwtTokenProvider,
                                           ObjectMapper objectMapper,
-                                          Authorizor authorizor) {
-        this.userDetailsService = userDetailsService;
+                                          Authorizer authorizor) {
         this.jwtTokenProvider = jwtTokenProvider;
         this.objectMapper = objectMapper;
         this.authorizor = authorizor;
@@ -34,7 +30,7 @@ public TokenAuthenticationInterceptor(UserDetailsService userDetailsService,
     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
         AuthenticationToken authenticationToken = convert(request);
-        Authentication authentication = authenticate(authenticationToken);
+        Authentication authentication = authorizor.authenticate(authenticationToken);
 
         final String payload = objectMapper.writeValueAsString(authentication.getPrincipal());
         final String token = jwtTokenProvider.createToken(payload);
@@ -49,14 +45,6 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons
         return false;
     }
 
-    public Authentication authenticate(AuthenticationToken authenticationToken) {
-        final String principal = authenticationToken.getPrincipal();
-        final User userDetails = userDetailsService.loadUserByUsername(principal);
-        authorizor.checkAuthentication(userDetails, authenticationToken);
-
-        return new Authentication(userDetails);
-    }
-
     @Override
     public AuthenticationToken convert(HttpServletRequest request) throws IOException {
         TokenRequest tokenRequest = objectMapper.readValue(request.getInputStream(), TokenRequest.class);
diff --git a/src/test/java/nextstep/subway/unit/TokenAuthenticationInterceptorTest.java b/src/test/java/nextstep/subway/unit/TokenAuthenticationInterceptorTest.java
index 719f4157e..8c6766c87 100644
--- a/src/test/java/nextstep/subway/unit/TokenAuthenticationInterceptorTest.java
+++ b/src/test/java/nextstep/subway/unit/TokenAuthenticationInterceptorTest.java
@@ -2,7 +2,7 @@
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import nextstep.auth.authentication.AuthenticationToken;
-import nextstep.auth.authentication.Authorizor;
+import nextstep.auth.authentication.Authorizer;
 import nextstep.auth.authentication.TokenAuthenticationInterceptor;
 import nextstep.auth.context.Authentication;
 import nextstep.auth.token.JwtTokenProvider;
@@ -35,7 +35,7 @@ class TokenAuthenticationInterceptorTest {
     public static final String JWT_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjJ9.ih1aovtQShabQ7l0cINw4k1fagApg3qLWiB8Kt59Lno";
 
     private ObjectMapper objectMapper;
-    private Authorizor authorizor;
+    private Authorizer authorizor;
 
     @Mock
     private CustomUserDetailsService userDetailsService;
@@ -46,13 +46,13 @@ class TokenAuthenticationInterceptorTest {
     @BeforeEach
     void init() {
         objectMapper = new ObjectMapper();
-        authorizor = new Authorizor();
+        authorizor = new Authorizer(userDetailsService);
     }
 
     @Test
     void convert() throws IOException {
         // given
-        TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(userDetailsService, jwtTokenProvider, objectMapper, authorizor);
+        TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(jwtTokenProvider, objectMapper, authorizor);
         MockHttpServletRequest request = createMockRequest();
 
         // when
@@ -65,19 +65,19 @@ void convert() throws IOException {
 
     @Test
     void authenticate() {
-        TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(userDetailsService, jwtTokenProvider, objectMapper, authorizor);
+        TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(jwtTokenProvider, objectMapper, authorizor);
 
         when(userDetailsService.loadUserByUsername(EMAIL)).thenReturn(new LoginMember(1L, EMAIL, PASSWORD, 20));
 
         AuthenticationToken authenticationToken = new AuthenticationToken(EMAIL, PASSWORD);
-        Authentication authentication = interceptor.authenticate(authenticationToken);
+        Authentication authentication = authorizor.authenticate(authenticationToken);
 
         assertThat(authentication.getPrincipal()).isNotNull();
     }
 
     @Test
     void preHandle() throws IOException, JSONException {
-        TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(userDetailsService, jwtTokenProvider, objectMapper, authorizor);
+        TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(jwtTokenProvider, objectMapper, authorizor);
 
         when(userDetailsService.loadUserByUsername(EMAIL)).thenReturn(new LoginMember(1L, EMAIL, PASSWORD, 20));
         when(jwtTokenProvider.createToken(anyString())).thenReturn(JWT_TOKEN);

From d6285c737a0ccec33e498049e2591e6bb27f8763 Mon Sep 17 00:00:00 2001
From: minyul <ggomjae@gmail.com>
Date: Wed, 23 Feb 2022 18:51:12 +0900
Subject: [PATCH 03/10] =?UTF-8?q?test=20:=20test=20=ED=8B=80=20=EB=A7=8C?=
 =?UTF-8?q?=EB=93=A4=EA=B8=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../acceptance/FavoritesAcceptanceTest.java   | 54 +++++++++++++++++++
 1 file changed, 54 insertions(+)
 create mode 100644 src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java

diff --git a/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
new file mode 100644
index 000000000..35bc7d6ef
--- /dev/null
+++ b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
@@ -0,0 +1,54 @@
+package nextstep.subway.acceptance;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+@DisplayName("즐겨찾기")
+public class FavoritesAcceptanceTest extends AcceptanceTest {
+
+	/**
+	 *     Given 지하철역 등록되어 있음
+	 *     And 지하철 노선 등록되어 있음
+	 *     And 지하철 노선에 지하철역 등록되어 있음
+	 *     And 회원 등록되어 있음
+	 *     And 로그인 되어있음
+	 */
+	private void init() {
+
+	}
+
+	/**
+	 *     When 즐겨찾기 생성을 요청
+	 *     Then 즐겨찾기 생성됨
+	 */
+	@DisplayName("즐겨찾기를 생성하다.")
+	@Test
+	void createFavorites() {
+		init();
+
+	}
+
+	/**
+	 *  	 given 즐겨찾기 생성
+	 *     When 즐겨찾기 목록 조회 요청
+	 *     Then 즐겨찾기 목록 조회됨
+	 */
+	@DisplayName("즐겨찾기를 조회하다.")
+	@Test
+	void showFavorites() {
+		init();
+
+	}
+
+	/**
+	 * 		given 즐겨찾기 생성
+	 *    When 즐겨찾기 삭제 요청
+	 *    Then 즐겨찾기 삭제됨
+	 */
+	@DisplayName("즐가찾기를 삭제하다")
+	@Test
+	void removeFavorites() {
+		init();
+
+	}
+}
\ No newline at end of file

From 93395aae2ba34adf134c6ecd155d05b4e094e523 Mon Sep 17 00:00:00 2001
From: minyul <ggomjae@gmail.com>
Date: Wed, 23 Feb 2022 19:44:13 +0900
Subject: [PATCH 04/10] =?UTF-8?q?feat=20&=20test=20:=20=EC=A6=90=EA=B2=A8?=
 =?UTF-8?q?=EC=B0=BE=EA=B8=B0=20=EC=83=9D=EC=84=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../member/application/MemberService.java     | 27 +++++++--
 .../application/dto/FavoriteRequest.java      | 15 +++++
 .../application/dto/FavoriteResponse.java     | 37 ++++++++++++
 .../java/nextstep/member/domain/Favorite.java | 49 ++++++++++++++++
 .../member/domain/FavoriteRepository.java     |  7 +++
 .../nextstep/member/ui/MemberController.java  | 12 ++++
 .../acceptance/FavoritesAcceptanceTest.java   | 57 +++++++++++++++++--
 .../subway/acceptance/FavoritesSteps.java     | 30 ++++++++++
 8 files changed, 225 insertions(+), 9 deletions(-)
 create mode 100644 src/main/java/nextstep/member/application/dto/FavoriteRequest.java
 create mode 100644 src/main/java/nextstep/member/application/dto/FavoriteResponse.java
 create mode 100644 src/main/java/nextstep/member/domain/Favorite.java
 create mode 100644 src/main/java/nextstep/member/domain/FavoriteRepository.java
 create mode 100644 src/test/java/nextstep/subway/acceptance/FavoritesSteps.java

diff --git a/src/main/java/nextstep/member/application/MemberService.java b/src/main/java/nextstep/member/application/MemberService.java
index 434adea8a..eecee6cae 100644
--- a/src/main/java/nextstep/member/application/MemberService.java
+++ b/src/main/java/nextstep/member/application/MemberService.java
@@ -1,18 +1,27 @@
 package nextstep.member.application;
 
+import nextstep.member.application.dto.FavoriteRequest;
+import nextstep.member.application.dto.FavoriteResponse;
 import nextstep.member.application.dto.MemberRequest;
 import nextstep.member.application.dto.MemberResponse;
-import nextstep.member.domain.LoginMember;
-import nextstep.member.domain.Member;
-import nextstep.member.domain.MemberRepository;
+import nextstep.member.domain.*;
+import nextstep.subway.applicaion.StationService;
+import nextstep.subway.domain.Station;
 import org.springframework.stereotype.Service;
 
 @Service
 public class MemberService {
+
     private MemberRepository memberRepository;
+    private FavoriteRepository favoriteRepository;
+    private StationService stationService;
 
-    public MemberService(MemberRepository memberRepository) {
+    public MemberService(MemberRepository memberRepository,
+                         FavoriteRepository favoriteRepository,
+                         StationService stationService) {
         this.memberRepository = memberRepository;
+        this.favoriteRepository = favoriteRepository;
+        this.stationService = stationService;
     }
 
     public MemberResponse createMember(MemberRequest request) {
@@ -53,4 +62,14 @@ public void deleteMemberOfMine(LoginMember loginMember) {
         Member member = memberRepository.findByEmail(loginMember.getEmail()).orElseThrow(RuntimeException::new);
         memberRepository.delete(member);
     }
+
+    public FavoriteResponse createFavorite(LoginMember loginMember, FavoriteRequest favoriteRequest) {
+        Member member = memberRepository.findById(loginMember.getId()).orElseThrow(RuntimeException::new);
+        Station source = stationService.findById(favoriteRequest.getSource());
+        Station target = stationService.findById(favoriteRequest.getTarget());
+        Favorite favorite = new Favorite(member, source, target);
+        favoriteRepository.save(favorite);
+
+        return FavoriteResponse.of(favorite);
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/nextstep/member/application/dto/FavoriteRequest.java b/src/main/java/nextstep/member/application/dto/FavoriteRequest.java
new file mode 100644
index 000000000..09e9556e0
--- /dev/null
+++ b/src/main/java/nextstep/member/application/dto/FavoriteRequest.java
@@ -0,0 +1,15 @@
+package nextstep.member.application.dto;
+
+public class FavoriteRequest {
+
+	private Long source;
+	private Long target;
+
+	public Long getSource() {
+		return source;
+	}
+
+	public Long getTarget() {
+		return target;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/nextstep/member/application/dto/FavoriteResponse.java b/src/main/java/nextstep/member/application/dto/FavoriteResponse.java
new file mode 100644
index 000000000..8065ada60
--- /dev/null
+++ b/src/main/java/nextstep/member/application/dto/FavoriteResponse.java
@@ -0,0 +1,37 @@
+package nextstep.member.application.dto;
+
+import nextstep.member.domain.Favorite;
+import nextstep.subway.applicaion.dto.StationResponse;
+
+public class FavoriteResponse {
+
+	private Long id;
+	private StationResponse source;
+	private StationResponse target;
+
+	public static FavoriteResponse of(Favorite favorite) {
+
+		return new FavoriteResponse(
+						favorite.getId(),
+						StationResponse.of(favorite.getSource()),
+						StationResponse.of(favorite.getTarget()));
+	}
+
+	public FavoriteResponse(Long id, StationResponse source, StationResponse target) {
+		this.id = id;
+		this.source = source;
+		this.target = target;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public StationResponse getSource() {
+		return source;
+	}
+
+	public StationResponse getTarget() {
+		return target;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/nextstep/member/domain/Favorite.java b/src/main/java/nextstep/member/domain/Favorite.java
new file mode 100644
index 000000000..c9e1c8c06
--- /dev/null
+++ b/src/main/java/nextstep/member/domain/Favorite.java
@@ -0,0 +1,49 @@
+package nextstep.member.domain;
+
+import nextstep.subway.domain.Station;
+
+import javax.persistence.*;
+
+@Entity
+public class Favorite {
+
+	@Id
+	@GeneratedValue(strategy = GenerationType.IDENTITY)
+	private Long id;
+
+	@ManyToOne(cascade = CascadeType.PERSIST)
+	@JoinColumn(name = "member_id")
+	private Member member;
+
+	@ManyToOne(cascade = CascadeType.PERSIST)
+	@JoinColumn(name = "up_station_id")
+	private Station source;
+
+	@ManyToOne(cascade = CascadeType.PERSIST)
+	@JoinColumn(name = "down_station_id")
+	private Station target;
+
+	protected Favorite() {}
+
+	public Favorite(Member member, Station source, Station target) {
+		this.member = member;
+		this.source = source;
+		this.target = target;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public Member getMember() {
+		return member;
+	}
+
+	public Station getSource() {
+		return source;
+	}
+
+	public Station getTarget() {
+		return target;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/nextstep/member/domain/FavoriteRepository.java b/src/main/java/nextstep/member/domain/FavoriteRepository.java
new file mode 100644
index 000000000..862afd78f
--- /dev/null
+++ b/src/main/java/nextstep/member/domain/FavoriteRepository.java
@@ -0,0 +1,7 @@
+package nextstep.member.domain;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface FavoriteRepository extends JpaRepository<Favorite, Long> {
+
+}
\ No newline at end of file
diff --git a/src/main/java/nextstep/member/ui/MemberController.java b/src/main/java/nextstep/member/ui/MemberController.java
index 96c4f7528..495c39062 100644
--- a/src/main/java/nextstep/member/ui/MemberController.java
+++ b/src/main/java/nextstep/member/ui/MemberController.java
@@ -4,6 +4,8 @@
 import nextstep.auth.context.SecurityContext;
 import nextstep.auth.context.SecurityContextHolder;
 import nextstep.member.application.MemberService;
+import nextstep.member.application.dto.FavoriteRequest;
+import nextstep.member.application.dto.FavoriteResponse;
 import nextstep.member.application.dto.MemberRequest;
 import nextstep.member.application.dto.MemberResponse;
 import nextstep.member.domain.LoginMember;
@@ -69,5 +71,15 @@ public ResponseEntity<MemberResponse> deleteMemberOfMine(@AuthenticationPrincipa
 
         return ResponseEntity.noContent().build();
     }
+
+    @PostMapping("/favorites")
+    public ResponseEntity<Void> createFavorite(
+            @AuthenticationPrincipal LoginMember loginMember,
+            @RequestBody FavoriteRequest request
+    ) {
+        FavoriteResponse favorite = memberService.createFavorite(loginMember, request);
+
+        return ResponseEntity.created(URI.create("/favorites/" + favorite.getId())).build();
+    }
 }
 
diff --git a/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
index 35bc7d6ef..a889943cb 100644
--- a/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
+++ b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
@@ -1,11 +1,29 @@
 package nextstep.subway.acceptance;
 
+import io.restassured.response.ExtractableResponse;
+import io.restassured.response.Response;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Test;
+import org.springframework.http.HttpStatus;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static nextstep.subway.acceptance.FavoritesSteps.즐겨찾기_생성_요청;
+import static nextstep.subway.acceptance.LineSteps.지하철_노선_생성_요청;
+import static nextstep.subway.acceptance.MemberSteps.로그인_되어_있음;
+import static nextstep.subway.acceptance.MemberSteps.회원_생성_요청;
+import static nextstep.subway.acceptance.StationSteps.지하철역_생성_요청;
+import static org.assertj.core.api.Assertions.assertThat;
 
 @DisplayName("즐겨찾기")
 public class FavoritesAcceptanceTest extends AcceptanceTest {
 
+	private static final String EMAIL = "email@email.com";
+	private static final String PASSWORD = "password";
+	private static final Integer AGE = 20;
+
 	/**
 	 *     Given 지하철역 등록되어 있음
 	 *     And 지하철 노선 등록되어 있음
@@ -13,8 +31,21 @@ public class FavoritesAcceptanceTest extends AcceptanceTest {
 	 *     And 회원 등록되어 있음
 	 *     And 로그인 되어있음
 	 */
-	private void init() {
 
+	private Long 강남역;
+	private Long 양재역;
+	private Long 신분당선;
+	private String accessToken;
+
+	@BeforeEach
+	private void init() {
+		super.setUp();
+		강남역 = 지하철역_생성_요청("강남역").jsonPath().getLong("id");
+		양재역 = 지하철역_생성_요청("양재역").jsonPath().getLong("id");
+		Map<String, String> lineCreateParams = createLineCreateParams(강남역, 양재역);
+		신분당선 = 지하철_노선_생성_요청(lineCreateParams).jsonPath().getLong("id");
+		회원_생성_요청(EMAIL, PASSWORD, AGE);
+		accessToken = 로그인_되어_있음(EMAIL, PASSWORD);
 	}
 
 	/**
@@ -24,8 +55,12 @@ private void init() {
 	@DisplayName("즐겨찾기를 생성하다.")
 	@Test
 	void createFavorites() {
-		init();
+		// when
+		ExtractableResponse<Response> result = 즐겨찾기_생성_요청(accessToken, 강남역, 양재역);
 
+		// then
+		assertThat(result.response().statusCode()).isEqualTo(HttpStatus.CREATED.value());
+		assertThat(result.header("Location")).isNotBlank();
 	}
 
 	/**
@@ -36,7 +71,7 @@ void createFavorites() {
 	@DisplayName("즐겨찾기를 조회하다.")
 	@Test
 	void showFavorites() {
-		init();
+
 
 	}
 
@@ -48,7 +83,19 @@ void showFavorites() {
 	@DisplayName("즐가찾기를 삭제하다")
 	@Test
 	void removeFavorites() {
-		init();
 
+
+	}
+
+	private Map<String, String> createLineCreateParams(Long upStationId, Long downStationId) {
+		Map<String, String> lineCreateParams;
+		lineCreateParams = new HashMap<>();
+		lineCreateParams.put("name", "신분당선");
+		lineCreateParams.put("color", "bg-red-600");
+		lineCreateParams.put("upStationId", upStationId + "");
+		lineCreateParams.put("downStationId", downStationId + "");
+		lineCreateParams.put("distance", 10 + "");
+
+		return lineCreateParams;
 	}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java b/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java
new file mode 100644
index 000000000..c3526a235
--- /dev/null
+++ b/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java
@@ -0,0 +1,30 @@
+package nextstep.subway.acceptance;
+
+import io.restassured.RestAssured;
+import io.restassured.response.ExtractableResponse;
+import io.restassured.response.Response;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class FavoritesSteps {
+
+	public static ExtractableResponse<Response> 즐겨찾기_생성_요청(final String accessToken, final Long source, final Long target) {
+
+		Map<String, String> favorites;
+		favorites = new HashMap<>();
+		favorites.put("source", source + "");
+		favorites.put("target", target + "");
+
+		return RestAssured.given().log().all()
+						.auth().oauth2(accessToken)
+						.body(favorites)
+						.contentType(MediaType.APPLICATION_JSON_VALUE)
+						.when().post("/favorites")
+						.then().log().all()
+						.statusCode(HttpStatus.CREATED.value())
+						.extract();
+	}
+}

From ff5dd7502e326e7674e43b93e8e8dd7d33df5b1e Mon Sep 17 00:00:00 2001
From: minyul <ggomjae@gmail.com>
Date: Wed, 23 Feb 2022 20:17:15 +0900
Subject: [PATCH 05/10] =?UTF-8?q?test=20&=20feat=20:=20=EC=A6=90=EA=B2=A8?=
 =?UTF-8?q?=EC=B0=BE=EA=B8=B0=EB=A5=BC=20=EC=A1=B0=ED=9A=8C=ED=95=98?=
 =?UTF-8?q?=EB=8B=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../member/application/MemberService.java     | 11 ++++++++
 .../nextstep/member/domain/Favorites.java     | 27 +++++++++++++++++++
 .../java/nextstep/member/domain/Member.java   | 21 ++++++++++++---
 .../nextstep/member/ui/MemberController.java  |  8 ++++++
 .../acceptance/FavoritesAcceptanceTest.java   |  8 ++++++
 .../subway/acceptance/FavoritesSteps.java     | 11 ++++++++
 6 files changed, 82 insertions(+), 4 deletions(-)
 create mode 100644 src/main/java/nextstep/member/domain/Favorites.java

diff --git a/src/main/java/nextstep/member/application/MemberService.java b/src/main/java/nextstep/member/application/MemberService.java
index eecee6cae..e841edee1 100644
--- a/src/main/java/nextstep/member/application/MemberService.java
+++ b/src/main/java/nextstep/member/application/MemberService.java
@@ -9,6 +9,9 @@
 import nextstep.subway.domain.Station;
 import org.springframework.stereotype.Service;
 
+import java.util.List;
+import java.util.stream.Collectors;
+
 @Service
 public class MemberService {
 
@@ -72,4 +75,12 @@ public FavoriteResponse createFavorite(LoginMember loginMember, FavoriteRequest
 
         return FavoriteResponse.of(favorite);
     }
+
+    public List<FavoriteResponse> findFavoritesOfMine(LoginMember loginMember) {
+        Member member = memberRepository.findById(loginMember.getId()).orElseThrow(RuntimeException::new);
+
+        return member.getFavorites().stream()
+                .map(FavoriteResponse::of)
+                .collect(Collectors.toList());
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/nextstep/member/domain/Favorites.java b/src/main/java/nextstep/member/domain/Favorites.java
new file mode 100644
index 000000000..c11dc3a21
--- /dev/null
+++ b/src/main/java/nextstep/member/domain/Favorites.java
@@ -0,0 +1,27 @@
+package nextstep.member.domain;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Embeddable;
+import javax.persistence.OneToMany;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Embeddable
+public class Favorites {
+
+	@OneToMany(mappedBy = "member", cascade = {CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval = true)
+	private List<Favorite> favorites = new ArrayList<>();
+
+	public void add(Favorite favorite) {
+		this.favorites.add(favorite);
+	}
+
+	public void remove(Favorite favorite) {
+		this.favorites.remove(favorite);
+	}
+
+	public List<Favorite> getFavorites() {
+		return Collections.unmodifiableList(favorites);
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/nextstep/member/domain/Member.java b/src/main/java/nextstep/member/domain/Member.java
index 09ce656ed..0deb5cfaf 100644
--- a/src/main/java/nextstep/member/domain/Member.java
+++ b/src/main/java/nextstep/member/domain/Member.java
@@ -2,10 +2,8 @@
 
 import nextstep.subway.domain.BaseEntity;
 
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
+import javax.persistence.*;
+import java.util.List;
 
 @Entity
 public class Member extends BaseEntity {
@@ -16,6 +14,9 @@ public class Member extends BaseEntity {
     private String password;
     private Integer age;
 
+    @Embedded
+    private Favorites favorites = new Favorites();
+
     protected Member() {
 
     }
@@ -47,4 +48,16 @@ public void update(Member member) {
         this.password = member.password;
         this.age = member.age;
     }
+
+    public List<Favorite> getFavorites() {
+        return favorites.getFavorites();
+    }
+
+    public void addFavorite(Favorite favorite) {
+        this.favorites.add(favorite);
+    }
+
+    public void removeFavorite(Favorite favorite) {
+        this.favorites.remove(favorite);
+    }
 }
diff --git a/src/main/java/nextstep/member/ui/MemberController.java b/src/main/java/nextstep/member/ui/MemberController.java
index 495c39062..8af4c7838 100644
--- a/src/main/java/nextstep/member/ui/MemberController.java
+++ b/src/main/java/nextstep/member/ui/MemberController.java
@@ -13,6 +13,7 @@
 import org.springframework.web.bind.annotation.*;
 
 import java.net.URI;
+import java.util.List;
 
 @RestController
 public class MemberController {
@@ -81,5 +82,12 @@ public ResponseEntity<Void> createFavorite(
 
         return ResponseEntity.created(URI.create("/favorites/" + favorite.getId())).build();
     }
+
+    @GetMapping("/favorites")
+    public ResponseEntity<List<FavoriteResponse>> findFavoritesOfMine(@AuthenticationPrincipal LoginMember loginMember) {
+        List<FavoriteResponse> favoriteResponses = memberService.findFavoritesOfMine(loginMember);
+
+        return ResponseEntity.ok().body(favoriteResponses);
+    }
 }
 
diff --git a/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
index a889943cb..4bb42b40f 100644
--- a/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
+++ b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
@@ -10,6 +10,7 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import static nextstep.subway.acceptance.FavoritesSteps.즐겨찾기_목록_조회;
 import static nextstep.subway.acceptance.FavoritesSteps.즐겨찾기_생성_요청;
 import static nextstep.subway.acceptance.LineSteps.지하철_노선_생성_요청;
 import static nextstep.subway.acceptance.MemberSteps.로그인_되어_있음;
@@ -71,8 +72,15 @@ void createFavorites() {
 	@DisplayName("즐겨찾기를 조회하다.")
 	@Test
 	void showFavorites() {
+		// given
+		즐겨찾기_생성_요청(accessToken, 강남역, 양재역);
 
+		// when
+		ExtractableResponse<Response> result = 즐겨찾기_목록_조회(accessToken);
 
+		// then
+		assertThat(result.statusCode()).isEqualTo(HttpStatus.OK.value());
+		assertThat(result.jsonPath().getList("id")).hasSize(1).containsExactly(1);
 	}
 
 	/**
diff --git a/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java b/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java
index c3526a235..e44ee8816 100644
--- a/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java
+++ b/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java
@@ -27,4 +27,15 @@ public class FavoritesSteps {
 						.statusCode(HttpStatus.CREATED.value())
 						.extract();
 	}
+
+	public static ExtractableResponse<Response> 즐겨찾기_목록_조회(final String accessToken) {
+
+		return RestAssured.given().log().all()
+						.auth().oauth2(accessToken)
+						.accept(MediaType.APPLICATION_JSON_VALUE)
+						.when().get("/favorites")
+						.then().log().all()
+						.statusCode(HttpStatus.OK.value())
+						.extract();
+	}
 }

From d838e0ae598241534bbbbda448a2e0fa53bbd15f Mon Sep 17 00:00:00 2001
From: minyul <ggomjae@gmail.com>
Date: Wed, 23 Feb 2022 20:27:05 +0900
Subject: [PATCH 06/10] =?UTF-8?q?test=20&=20feat=20:=20=EC=A6=90=EA=B2=A8?=
 =?UTF-8?q?=EC=B0=BE=EA=B8=B0=EB=A5=BC=20=EC=82=AD=EC=A0=9C=ED=95=98?=
 =?UTF-8?q?=EB=8B=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../nextstep/member/application/MemberService.java     |  7 +++++++
 src/main/java/nextstep/member/ui/MemberController.java | 10 ++++++++++
 .../subway/acceptance/FavoritesAcceptanceTest.java     |  9 +++++++--
 .../nextstep/subway/acceptance/FavoritesSteps.java     |  9 +++++++++
 4 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/src/main/java/nextstep/member/application/MemberService.java b/src/main/java/nextstep/member/application/MemberService.java
index e841edee1..9636cdade 100644
--- a/src/main/java/nextstep/member/application/MemberService.java
+++ b/src/main/java/nextstep/member/application/MemberService.java
@@ -83,4 +83,11 @@ public List<FavoriteResponse> findFavoritesOfMine(LoginMember loginMember) {
                 .map(FavoriteResponse::of)
                 .collect(Collectors.toList());
     }
+
+    public void deleteFavorite(LoginMember loginMember, Long favoriteId) {
+        Member member = memberRepository.findById(loginMember.getId()).orElseThrow(RuntimeException::new);
+        Favorite favorite = favoriteRepository.findById(favoriteId).orElseThrow(RuntimeException::new);
+
+        member.removeFavorite(favorite);
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/nextstep/member/ui/MemberController.java b/src/main/java/nextstep/member/ui/MemberController.java
index 8af4c7838..89b27fe4b 100644
--- a/src/main/java/nextstep/member/ui/MemberController.java
+++ b/src/main/java/nextstep/member/ui/MemberController.java
@@ -89,5 +89,15 @@ public ResponseEntity<List<FavoriteResponse>> findFavoritesOfMine(@Authenticatio
 
         return ResponseEntity.ok().body(favoriteResponses);
     }
+
+    @DeleteMapping("/favorites/{favoriteId}")
+    public ResponseEntity<MemberResponse> deleteFavoriteOfMine(
+            @AuthenticationPrincipal LoginMember loginMember,
+            @PathVariable Long favoriteId
+    ) {
+        memberService.deleteFavorite(loginMember, favoriteId);
+
+        return ResponseEntity.noContent().build();
+    }
 }
 
diff --git a/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
index 4bb42b40f..5edb89b6b 100644
--- a/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
+++ b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
@@ -10,8 +10,7 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import static nextstep.subway.acceptance.FavoritesSteps.즐겨찾기_목록_조회;
-import static nextstep.subway.acceptance.FavoritesSteps.즐겨찾기_생성_요청;
+import static nextstep.subway.acceptance.FavoritesSteps.*;
 import static nextstep.subway.acceptance.LineSteps.지하철_노선_생성_요청;
 import static nextstep.subway.acceptance.MemberSteps.로그인_되어_있음;
 import static nextstep.subway.acceptance.MemberSteps.회원_생성_요청;
@@ -91,8 +90,14 @@ void showFavorites() {
 	@DisplayName("즐가찾기를 삭제하다")
 	@Test
 	void removeFavorites() {
+		// given
+		즐겨찾기_생성_요청(accessToken, 강남역, 양재역);
 
+		// when
+		ExtractableResponse<Response> result = 즐겨찾기_삭제(accessToken, 1L);
 
+		// then
+		assertThat(result.statusCode()).isEqualTo(HttpStatus.NO_CONTENT.value());
 	}
 
 	private Map<String, String> createLineCreateParams(Long upStationId, Long downStationId) {
diff --git a/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java b/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java
index e44ee8816..28e47594a 100644
--- a/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java
+++ b/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java
@@ -38,4 +38,13 @@ public class FavoritesSteps {
 						.statusCode(HttpStatus.OK.value())
 						.extract();
 	}
+
+	public static ExtractableResponse<Response> 즐겨찾기_삭제(final String accessToken, final Long id) {
+
+		return RestAssured
+						.given().log().all()
+						.auth().oauth2(accessToken)
+						.when().delete("/favorites/{favoriteId}", id)
+						.then().log().all().extract();
+	}
 }

From a21678bd44155ccb19a8e6bcbfb9832c7b356f34 Mon Sep 17 00:00:00 2001
From: minyul <ggomjae@gmail.com>
Date: Sat, 26 Feb 2022 16:59:33 +0900
Subject: [PATCH 07/10] =?UTF-8?q?refactor=20:=20Authorizer=20=EB=82=B4?=
 =?UTF-8?q?=EB=B6=80=20=EB=A9=94=EC=86=8C=EB=93=9C=20checkAuthentication?=
 =?UTF-8?q?=20:=20public=20->=20private?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../auth/authentication/Authorizer.java        | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/main/java/nextstep/auth/authentication/Authorizer.java b/src/main/java/nextstep/auth/authentication/Authorizer.java
index 374259678..ea0ac67d0 100644
--- a/src/main/java/nextstep/auth/authentication/Authorizer.java
+++ b/src/main/java/nextstep/auth/authentication/Authorizer.java
@@ -13,7 +13,15 @@ public Authorizer(UserDetailsService userDetailsService) {
 		this.userDetailsService = userDetailsService;
 	}
 
-	public void checkAuthentication(User userDetails, AuthenticationToken token) {
+	public Authentication authenticate(AuthenticationToken authenticationToken) {
+		final String principal = authenticationToken.getPrincipal();
+		final User userDetails = userDetailsService.loadUserByUsername(principal);
+		checkAuthentication(userDetails, authenticationToken);
+
+		return new Authentication(userDetails);
+	}
+
+	private void checkAuthentication(User userDetails, AuthenticationToken token) {
 		if (ObjectUtils.isEmpty(userDetails)) {
 			throw new AuthenticationException();
 		}
@@ -22,12 +30,4 @@ public void checkAuthentication(User userDetails, AuthenticationToken token) {
 			throw new AuthenticationException();
 		}
 	}
-
-	public Authentication authenticate(AuthenticationToken authenticationToken) {
-		final String principal = authenticationToken.getPrincipal();
-		final User userDetails = userDetailsService.loadUserByUsername(principal);
-		checkAuthentication(userDetails, authenticationToken);
-
-		return new Authentication(userDetails);
-	}
 }

From 0c52d1aef260ce80448973f672ff86aac7766891 Mon Sep 17 00:00:00 2001
From: minyul <ggomjae@gmail.com>
Date: Sat, 26 Feb 2022 20:45:39 +0900
Subject: [PATCH 08/10] =?UTF-8?q?refactor=20&=20test=20:=20=EC=A6=90?=
 =?UTF-8?q?=EA=B2=A8=EC=B0=BE=EA=B8=B0=20=EC=A1=B0=ED=9A=8C=ED=95=98?=
 =?UTF-8?q?=EB=8A=94=20=EB=B6=80=EB=B6=84=EC=9D=84=20=EC=88=98=EC=A0=95?=
 =?UTF-8?q?=ED=95=98=EB=8B=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../nextstep/subway/acceptance/FavoritesAcceptanceTest.java     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
index 5edb89b6b..3dcaef6c7 100644
--- a/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
+++ b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
@@ -79,7 +79,7 @@ void showFavorites() {
 
 		// then
 		assertThat(result.statusCode()).isEqualTo(HttpStatus.OK.value());
-		assertThat(result.jsonPath().getList("id")).hasSize(1).containsExactly(1);
+		assertThat(result.jsonPath().getList("id", Long.class)).hasSize(1).containsExactly(1L);
 	}
 
 	/**

From b20453e713b8e0e0cfad1422b45b39468fad8305 Mon Sep 17 00:00:00 2001
From: minyul <ggomjae@gmail.com>
Date: Sat, 26 Feb 2022 21:14:28 +0900
Subject: [PATCH 09/10] =?UTF-8?q?feat=20&=20test=20:=20=EB=B9=84=EB=A1=9C?=
 =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EA=B2=BD=EC=9A=B0=20=EC=A6=90=EA=B2=A8?=
 =?UTF-8?q?=EC=B0=BE=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EC=82=AC?=
 =?UTF-8?q?=EC=9A=A9=ED=95=A0=20=EC=88=98=20=EC=97=86=EB=8B=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ...AuthenticationPrincipalArgumentResolver.java |  9 +++++++++
 .../acceptance/FavoritesAcceptanceTest.java     | 17 +++++++++++++++++
 .../subway/acceptance/FavoritesSteps.java       |  1 -
 3 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/src/main/java/nextstep/auth/authorization/AuthenticationPrincipalArgumentResolver.java b/src/main/java/nextstep/auth/authorization/AuthenticationPrincipalArgumentResolver.java
index 7c776cb80..47dc98171 100644
--- a/src/main/java/nextstep/auth/authorization/AuthenticationPrincipalArgumentResolver.java
+++ b/src/main/java/nextstep/auth/authorization/AuthenticationPrincipalArgumentResolver.java
@@ -1,8 +1,10 @@
 package nextstep.auth.authorization;
 
+import nextstep.auth.authentication.AuthenticationException;
 import nextstep.auth.context.Authentication;
 import nextstep.auth.context.SecurityContextHolder;
 import org.springframework.core.MethodParameter;
+import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.support.WebDataBinderFactory;
 import org.springframework.web.context.request.NativeWebRequest;
 import org.springframework.web.method.support.HandlerMethodArgumentResolver;
@@ -20,6 +22,7 @@ public boolean supportsParameter(MethodParameter parameter) {
     @Override
     public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
         Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+        authenticationValidate(authentication);
         if (authentication.getPrincipal() instanceof Map) {
             return extractPrincipal(parameter, authentication);
         }
@@ -27,6 +30,12 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m
         return authentication.getPrincipal();
     }
 
+    private void authenticationValidate(Authentication authentication) {
+        if (ObjectUtils.isEmpty(authentication)) {
+            throw new AuthenticationException();
+        }
+    }
+
     private Object extractPrincipal(MethodParameter parameter, Authentication authentication) {
         try {
             Map<String, String> principal = (Map) authentication.getPrincipal();
diff --git a/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
index 3dcaef6c7..270b39b1c 100644
--- a/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
+++ b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
@@ -100,6 +100,23 @@ void removeFavorites() {
 		assertThat(result.statusCode()).isEqualTo(HttpStatus.NO_CONTENT.value());
 	}
 
+	/**
+	 * 비로그인 경우 401 Unauthorized 응답
+	 */
+	@DisplayName("비로그인 즐겨찾기 기능을 사용할 수 없다.")
+	@Test
+	void  isUnauthorized() {
+		// given
+		즐겨찾기_생성_요청(accessToken, 강남역, 양재역);
+		accessToken = "";
+
+		// when
+		ExtractableResponse<Response> result = 즐겨찾기_목록_조회(accessToken);
+
+		// then
+		assertThat(result.statusCode()).isEqualTo(HttpStatus.UNAUTHORIZED.value());
+	}
+
 	private Map<String, String> createLineCreateParams(Long upStationId, Long downStationId) {
 		Map<String, String> lineCreateParams;
 		lineCreateParams = new HashMap<>();
diff --git a/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java b/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java
index 28e47594a..bc4de5d3c 100644
--- a/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java
+++ b/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java
@@ -35,7 +35,6 @@ public class FavoritesSteps {
 						.accept(MediaType.APPLICATION_JSON_VALUE)
 						.when().get("/favorites")
 						.then().log().all()
-						.statusCode(HttpStatus.OK.value())
 						.extract();
 	}
 

From cc6bcd8e149d45fbf28fda1345b4dcf561118673 Mon Sep 17 00:00:00 2001
From: minyul <ggomjae@gmail.com>
Date: Sat, 26 Feb 2022 22:25:58 +0900
Subject: [PATCH 10/10] =?UTF-8?q?refactor=20:=20=EA=B0=84=EC=A0=91?=
 =?UTF-8?q?=EC=B0=B8=EC=A1=B0=EB=A1=9C=20=EB=B0=94=EA=BE=B8=EB=8B=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../member/application/MemberService.java         |  8 ++++----
 .../java/nextstep/member/domain/Favorite.java     |  9 ++++-----
 .../member/domain/FavoriteRepository.java         |  4 ++++
 src/main/java/nextstep/member/domain/Member.java  | 15 ---------------
 .../acceptance/FavoritesAcceptanceTest.java       |  6 +++---
 5 files changed, 15 insertions(+), 27 deletions(-)

diff --git a/src/main/java/nextstep/member/application/MemberService.java b/src/main/java/nextstep/member/application/MemberService.java
index 9636cdade..154f9225a 100644
--- a/src/main/java/nextstep/member/application/MemberService.java
+++ b/src/main/java/nextstep/member/application/MemberService.java
@@ -70,7 +70,7 @@ public FavoriteResponse createFavorite(LoginMember loginMember, FavoriteRequest
         Member member = memberRepository.findById(loginMember.getId()).orElseThrow(RuntimeException::new);
         Station source = stationService.findById(favoriteRequest.getSource());
         Station target = stationService.findById(favoriteRequest.getTarget());
-        Favorite favorite = new Favorite(member, source, target);
+        Favorite favorite = new Favorite(member.getId(), source, target);
         favoriteRepository.save(favorite);
 
         return FavoriteResponse.of(favorite);
@@ -78,16 +78,16 @@ public FavoriteResponse createFavorite(LoginMember loginMember, FavoriteRequest
 
     public List<FavoriteResponse> findFavoritesOfMine(LoginMember loginMember) {
         Member member = memberRepository.findById(loginMember.getId()).orElseThrow(RuntimeException::new);
+        List<Favorite> favorites = favoriteRepository.findByMember(member.getId());
 
-        return member.getFavorites().stream()
+        return favorites.stream()
                 .map(FavoriteResponse::of)
                 .collect(Collectors.toList());
     }
 
     public void deleteFavorite(LoginMember loginMember, Long favoriteId) {
-        Member member = memberRepository.findById(loginMember.getId()).orElseThrow(RuntimeException::new);
         Favorite favorite = favoriteRepository.findById(favoriteId).orElseThrow(RuntimeException::new);
 
-        member.removeFavorite(favorite);
+        favoriteRepository.delete(favorite);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/nextstep/member/domain/Favorite.java b/src/main/java/nextstep/member/domain/Favorite.java
index c9e1c8c06..2ecca2f50 100644
--- a/src/main/java/nextstep/member/domain/Favorite.java
+++ b/src/main/java/nextstep/member/domain/Favorite.java
@@ -11,9 +11,8 @@ public class Favorite {
 	@GeneratedValue(strategy = GenerationType.IDENTITY)
 	private Long id;
 
-	@ManyToOne(cascade = CascadeType.PERSIST)
 	@JoinColumn(name = "member_id")
-	private Member member;
+	private Long member;
 
 	@ManyToOne(cascade = CascadeType.PERSIST)
 	@JoinColumn(name = "up_station_id")
@@ -25,8 +24,8 @@ public class Favorite {
 
 	protected Favorite() {}
 
-	public Favorite(Member member, Station source, Station target) {
-		this.member = member;
+	public Favorite(Long memberId, Station source, Station target) {
+		this.member = memberId;
 		this.source = source;
 		this.target = target;
 	}
@@ -35,7 +34,7 @@ public Long getId() {
 		return id;
 	}
 
-	public Member getMember() {
+	public Long getMember() {
 		return member;
 	}
 
diff --git a/src/main/java/nextstep/member/domain/FavoriteRepository.java b/src/main/java/nextstep/member/domain/FavoriteRepository.java
index 862afd78f..030c61525 100644
--- a/src/main/java/nextstep/member/domain/FavoriteRepository.java
+++ b/src/main/java/nextstep/member/domain/FavoriteRepository.java
@@ -2,6 +2,10 @@
 
 import org.springframework.data.jpa.repository.JpaRepository;
 
+import java.util.List;
+
 public interface FavoriteRepository extends JpaRepository<Favorite, Long> {
 
+
+	List<Favorite> findByMember(Long member);
 }
\ No newline at end of file
diff --git a/src/main/java/nextstep/member/domain/Member.java b/src/main/java/nextstep/member/domain/Member.java
index 0deb5cfaf..041a9d91b 100644
--- a/src/main/java/nextstep/member/domain/Member.java
+++ b/src/main/java/nextstep/member/domain/Member.java
@@ -14,9 +14,6 @@ public class Member extends BaseEntity {
     private String password;
     private Integer age;
 
-    @Embedded
-    private Favorites favorites = new Favorites();
-
     protected Member() {
 
     }
@@ -48,16 +45,4 @@ public void update(Member member) {
         this.password = member.password;
         this.age = member.age;
     }
-
-    public List<Favorite> getFavorites() {
-        return favorites.getFavorites();
-    }
-
-    public void addFavorite(Favorite favorite) {
-        this.favorites.add(favorite);
-    }
-
-    public void removeFavorite(Favorite favorite) {
-        this.favorites.remove(favorite);
-    }
 }
diff --git a/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
index 270b39b1c..efbe17e37 100644
--- a/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
+++ b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java
@@ -2,6 +2,7 @@
 
 import io.restassured.response.ExtractableResponse;
 import io.restassured.response.Response;
+import nextstep.auth.authentication.AuthenticationToken;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Test;
@@ -12,8 +13,7 @@
 
 import static nextstep.subway.acceptance.FavoritesSteps.*;
 import static nextstep.subway.acceptance.LineSteps.지하철_노선_생성_요청;
-import static nextstep.subway.acceptance.MemberSteps.로그인_되어_있음;
-import static nextstep.subway.acceptance.MemberSteps.회원_생성_요청;
+import static nextstep.subway.acceptance.MemberSteps.*;
 import static nextstep.subway.acceptance.StationSteps.지하철역_생성_요청;
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -105,7 +105,7 @@ void removeFavorites() {
 	 */
 	@DisplayName("비로그인 즐겨찾기 기능을 사용할 수 없다.")
 	@Test
-	void  isUnauthorized() {
+	void isUnauthorizedByLogin() {
 		// given
 		즐겨찾기_생성_요청(accessToken, 강남역, 양재역);
 		accessToken = "";