Return if the user logged in is a new member#148
Conversation
Summary of ChangesHello @choridev, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 이 PR은 로그인한 사용자가 신규 회원인지 여부를 프론트엔드에 전달하는 기능을 추가합니다. 이를 위해 인증 응답 객체에 신규 회원 여부 필드를 포함하고, 회원 생성 및 조회 로직을 개선하여 해당 정보를 효과적으로 관리하고 전달할 수 있도록 변경했습니다. 이로써 프론트엔드에서 신규 회원에 대한 맞춤형 경험을 제공할 수 있게 됩니다. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
로그인 시 신규 회원 여부를 반환하는 기능 추가에 대한 PR을 잘 보았습니다. 전반적으로 변경 사항은 명확하며, MemberCreationResult 레코드를 사용하여 findOrCreateMember 메서드가 멤버 객체와 신규 회원 여부를 함께 반환하도록 수정한 점이 좋습니다. 이를 통해 코드의 명확성이 향상되었습니다. 관련 서비스 및 DTO, 테스트 코드까지 모두 일관성 있게 수정된 점도 훌륭합니다. 한 가지 제안 사항으로, AuthServiceTest에 신규 사용자가 로그인하는 경우에 대한 테스트 케이스를 추가하면 login 메서드의 동작을 더 완벽하게 검증할 수 있을 것 같습니다.
| @DisplayName("Login successfully") | ||
| void Given_ValidLoginRequest_When_Login_Then_ReturnsAuthResponse() { | ||
| // given | ||
| final AuthRequest authRequest = new AuthRequest("facebook", idToken); | ||
| AuthRequest request = new AuthRequest("kakao", "id-token"); | ||
| Member member = Member.builder().id(1L).build(); | ||
| MemberCreationResult creationResult = new MemberCreationResult(member, false); | ||
| OidcClient oidcClient = mock(OidcClient.class); | ||
| OidcPublicKeys publicKeys = mock(OidcPublicKeys.class); | ||
|
|
||
| // when & then | ||
| final ServerException exception = assertThrows(ServerException.class, | ||
| () -> authService.login(authRequest)); | ||
|
|
||
| assertThat(exception.getErrorResult()).isEqualTo(AuthErrorResult.INVALID_PROVIDER); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("Issues tokens successfully when a registered Kakao member logs in") | ||
| void Given_RegisteredKakaoMember_When_Login_Then_IssuesTokensSuccessfully() { | ||
| // given | ||
| final AuthRequest authRequest = new AuthRequest("kakao", idToken); | ||
| final String providerId = "kakao-id-123"; | ||
| final OidcClient oidcClient = mock(OidcClient.class); | ||
| final OidcPublicKeys keys = mock(OidcPublicKeys.class); | ||
| final Member member = Member.builder().id(memberId).kakaoId(providerId).build(); | ||
|
|
||
| doReturn("nonce").when(jwtProvider).extractNonce(idToken); | ||
| doNothing().when(nonceService).verifyNonce("nonce", Provider.KAKAO); | ||
| doReturn("nonce").when(jwtProvider).extractNonce("id-token"); | ||
| doReturn(oidcClient).when(oidcClientFactory).getOidcClient(Provider.KAKAO); | ||
| doReturn(keys).when(oidcClient).getOidcPublicKeys(); | ||
| doReturn(providerId).when(oidcProviderFactory).getProviderId(Provider.KAKAO, idToken, keys); | ||
| doReturn(member).when(memberService).findOrCreateMember(Provider.KAKAO, providerId); | ||
| setupTokenIssuance(accessToken, refreshToken); | ||
|
|
||
| // when | ||
| final AuthResponse response = authService.login(authRequest); | ||
|
|
||
| // then | ||
| verify(nonceService).verifyNonce("nonce", Provider.KAKAO); | ||
| verify(refreshTokenService).saveRefreshToken(memberId, refreshToken); | ||
| assertThat(response.tokenType()).isEqualTo("Bearer"); | ||
| assertThat(response.accessToken()).isEqualTo(accessToken); | ||
| assertThat(response.refreshToken()).isEqualTo(refreshToken); | ||
| assertThat(response.accessTokenExpiresIn()).isEqualTo(accessTokenExpireTime); | ||
| assertThat(response.refreshTokenExpiresIn()).isEqualTo(refreshTokenExpireTime); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("Creates a new Kakao member and issues tokens on the first login") | ||
| void Given_NewKakaoMember_When_Login_Then_CreatesMemberAndIssuesTokens() { | ||
| // given | ||
| final AuthRequest authRequest = new AuthRequest("kakao", idToken); | ||
| final String providerId = "kakao-id-123"; | ||
| final OidcClient oidcClient = mock(OidcClient.class); | ||
| final OidcPublicKeys keys = mock(OidcPublicKeys.class); | ||
| final Member newMember = Member.builder().id(memberId).kakaoId(providerId).build(); | ||
| doReturn(publicKeys).when(oidcClient).getOidcPublicKeys(); | ||
| doReturn("provider-id").when(oidcProviderFactory).getProviderId(Provider.KAKAO, "id-token", publicKeys); | ||
| doReturn(creationResult).when(memberService).findOrCreateMember(Provider.KAKAO, "provider-id"); | ||
|
|
||
| doReturn("nonce").when(jwtProvider).extractNonce(idToken); | ||
| doReturn(oidcClient).when(oidcClientFactory).getOidcClient(Provider.KAKAO); | ||
| doReturn(keys).when(oidcClient).getOidcPublicKeys(); | ||
| doReturn(providerId).when(oidcProviderFactory).getProviderId(Provider.KAKAO, idToken, keys); | ||
| doReturn(newMember).when(memberService).findOrCreateMember(Provider.KAKAO, providerId); | ||
| setupTokenIssuance(accessToken, refreshToken); | ||
| doReturn("access-token").when(jwtProvider).generateAccessToken(1L); | ||
| doReturn("refresh-token").when(refreshTokenService).generateRefreshToken(); | ||
| doReturn("Bearer").when(jwtProperties).type(); | ||
| doReturn(3600).when(jwtProperties).accessTokenExpireTime(); | ||
| doReturn(1209600).when(jwtProperties).refreshTokenExpireTime(); | ||
|
|
||
| // when | ||
| final AuthResponse response = authService.login(authRequest); | ||
| AuthResponse response = authService.login(request); | ||
|
|
||
| // then | ||
| assertThat(response.accessToken()).isEqualTo("access-token"); | ||
| assertThat(response.isNewMember()).isFalse(); | ||
| verify(nonceService).verifyNonce("nonce", Provider.KAKAO); | ||
| verify(refreshTokenService).saveRefreshToken(memberId, refreshToken); | ||
| assertThat(response.accessToken()).isEqualTo(accessToken); | ||
| assertThat(response.refreshToken()).isEqualTo(refreshToken); | ||
| } |
There was a problem hiding this comment.
좋은 테스트 리팩토링입니다! login 메서드에 대한 테스트가 현재 기존 회원(isNewMember가 false인 경우)에 대해서만 검증하고 있습니다. 신규 회원이 로그인하는 경우(isNewMember가 true인 경우)에 대한 테스트 케이스를 추가하면 login 메서드의 모든 경로를 커버하여 안정성을 더욱 높일 수 있을 것 같습니다.
아래와 같은 테스트 케이스를 추가하는 것을 고려해 보세요:
@Test
@DisplayName("신규 유저 로그인 성공")
void Given_ValidLoginRequestForNewUser_When_Login_Then_ReturnsAuthResponseWithIsNewMemberTrue() {
// given
AuthRequest request = new AuthRequest("kakao", "id-token");
Member member = Member.builder().id(1L).build();
MemberCreationResult creationResult = new MemberCreationResult(member, true); // 신규 회원
OidcClient oidcClient = mock(OidcClient.class);
OidcPublicKeys publicKeys = mock(OidcPublicKeys.class);
doReturn("nonce").when(jwtProvider).extractNonce("id-token");
doReturn(oidcClient).when(oidcClientFactory).getOidcClient(Provider.KAKAO);
doReturn(publicKeys).when(oidcClient).getOidcPublicKeys();
doReturn("provider-id").when(oidcProviderFactory).getProviderId(Provider.KAKAO, "id-token", publicKeys);
doReturn(creationResult).when(memberService).findOrCreateMember(Provider.KAKAO, "provider-id");
doReturn("access-token").when(jwtProvider).generateAccessToken(1L);
doReturn("refresh-token").when(refreshTokenService).generateRefreshToken();
doReturn("Bearer").when(jwtProperties).type();
doReturn(3600).when(jwtProperties).accessTokenExpireTime();
doReturn(1209600).when(jwtProperties).refreshTokenExpireTime();
// when
AuthResponse response = authService.login(request);
// then
assertThat(response.accessToken()).isEqualTo("access-token");
assertThat(response.isNewMember()).isTrue(); // 신규 회원인지 검증
verify(nonceService).verifyNonce("nonce", Provider.KAKAO);
}
|



✅ PR 타입
반영 브랜치
feat/#147-check-new-member -> stg
✨ 변경 사항
로그인 시 기존 회원인지를 나타내는 정보를 프론트엔드로 반환합니다.
💯 테스트 결과
📂 관련 이슈
#147
👀 리뷰어에게