diff --git a/src/main/java/com/example/mate/domain/member/dto/response/MemberLoginResponse.java b/src/main/java/com/example/mate/domain/member/dto/response/MemberLoginResponse.java index 93ca9dae..4d1cb149 100644 --- a/src/main/java/com/example/mate/domain/member/dto/response/MemberLoginResponse.java +++ b/src/main/java/com/example/mate/domain/member/dto/response/MemberLoginResponse.java @@ -16,6 +16,10 @@ public class MemberLoginResponse { private final String grantType; private final String accessToken; private final String refreshToken; + private final String nickname; + private final Long teamId; + private final String gender; + private final Integer age; public static MemberLoginResponse from(Member member, JwtToken jwtToken) { return MemberLoginResponse.builder() @@ -23,6 +27,10 @@ public static MemberLoginResponse from(Member member, JwtToken jwtToken) { .grantType(jwtToken.getGrantType()) .accessToken(jwtToken.getAccessToken()) .refreshToken(jwtToken.getRefreshToken()) + .nickname(member.getNickname()) + .teamId(member.getTeamId()) + .gender(member.getGender().getValue()) + .age(member.getAge()) .build(); } } diff --git a/src/test/java/com/example/mate/domain/member/controller/MemberControllerTest.java b/src/test/java/com/example/mate/domain/member/controller/MemberControllerTest.java index 698937bc..2535f5cc 100644 --- a/src/test/java/com/example/mate/domain/member/controller/MemberControllerTest.java +++ b/src/test/java/com/example/mate/domain/member/controller/MemberControllerTest.java @@ -1,25 +1,14 @@ package com.example.mate.domain.member.controller; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.willDoNothing; -import static org.mockito.BDDMockito.willThrow; -import static org.mockito.Mockito.verify; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - import com.example.mate.common.error.CustomException; import com.example.mate.common.error.ErrorCode; import com.example.mate.common.security.filter.JwtCheckFilter; import com.example.mate.config.WithAuthMember; import com.example.mate.domain.member.dto.request.JoinRequest; import com.example.mate.domain.member.dto.request.MemberInfoUpdateRequest; +import com.example.mate.domain.member.dto.request.MemberLoginRequest; import com.example.mate.domain.member.dto.response.JoinResponse; +import com.example.mate.domain.member.dto.response.MemberLoginResponse; import com.example.mate.domain.member.dto.response.MemberProfileResponse; import com.example.mate.domain.member.dto.response.MyProfileResponse; import com.example.mate.domain.member.service.MemberService; @@ -37,6 +26,14 @@ import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.web.servlet.MockMvc; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.*; +import static org.mockito.Mockito.verify; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + @WebMvcTest(MemberController.class) @MockBean(JpaMetamodelMappingContext.class) @AutoConfigureMockMvc(addFilters = false) @@ -382,4 +379,44 @@ void delete_member_fail_not_exists_member() throws Exception { verify(memberService).deleteMember(memberId); } } + + @Nested + @DisplayName("회원 로그인") + class LoginMember { + + @Test + @DisplayName("회원 로그인 성공") + void login_member_success() throws Exception { + // given + MemberLoginRequest request = MemberLoginRequest.builder() + .email("test@example.com") + .build(); + + MemberLoginResponse response = MemberLoginResponse.builder() + .memberId(1L) + .grantType("Bearer") + .accessToken("accessToken") + .refreshToken("refreshToken") + .nickname("tester") + .teamId(1L) + .gender("남자") + .age(20) + .build(); + + given(memberService.loginByEmail(any(MemberLoginRequest.class))).willReturn(response); + + // when & then + mockMvc.perform(post("/api/members/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status").value("SUCCESS")) + .andExpect(jsonPath("$.data.memberId").value("1")) + .andExpect(jsonPath("$.data.nickname").value("tester")) + .andExpect(jsonPath("$.data.teamId").value("1")) + .andExpect(jsonPath("$.data.gender").value("남자")) + .andExpect(jsonPath("$.data.age").value("20")) + .andDo(print()); + } + } } \ No newline at end of file diff --git a/src/test/java/com/example/mate/domain/member/integration/MemberIntegrationTest.java b/src/test/java/com/example/mate/domain/member/integration/MemberIntegrationTest.java index 44f3f532..42f6081d 100644 --- a/src/test/java/com/example/mate/domain/member/integration/MemberIntegrationTest.java +++ b/src/test/java/com/example/mate/domain/member/integration/MemberIntegrationTest.java @@ -1,17 +1,7 @@ package com.example.mate.domain.member.integration; -import static com.example.mate.domain.match.entity.MatchStatus.SCHEDULED; -import static com.example.mate.domain.mate.entity.Status.CLOSED; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import com.example.mate.config.WithAuthMember; import com.example.mate.common.security.util.JwtUtil; +import com.example.mate.config.WithAuthMember; import com.example.mate.domain.constant.Gender; import com.example.mate.domain.constant.Rating; import com.example.mate.domain.goods.dto.LocationInfo; @@ -23,26 +13,20 @@ import com.example.mate.domain.goods.repository.GoodsReviewRepository; import com.example.mate.domain.match.entity.Match; import com.example.mate.domain.match.repository.MatchRepository; -import com.example.mate.domain.mate.entity.Age; -import com.example.mate.domain.mate.entity.MatePost; -import com.example.mate.domain.mate.entity.MateReview; -import com.example.mate.domain.mate.entity.TransportType; -import com.example.mate.domain.mate.entity.Visit; -import com.example.mate.domain.mate.entity.VisitPart; +import com.example.mate.domain.mate.entity.*; import com.example.mate.domain.mate.repository.MateRepository; import com.example.mate.domain.mate.repository.MateReviewRepository; import com.example.mate.domain.mate.repository.VisitPartRepository; import com.example.mate.domain.mate.repository.VisitRepository; import com.example.mate.domain.member.dto.request.JoinRequest; import com.example.mate.domain.member.dto.request.MemberInfoUpdateRequest; +import com.example.mate.domain.member.dto.request.MemberLoginRequest; import com.example.mate.domain.member.entity.Follow; import com.example.mate.domain.member.entity.Member; import com.example.mate.domain.member.repository.FollowRepository; import com.example.mate.domain.member.repository.MemberRepository; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.persistence.EntityManager; -import java.time.LocalDateTime; -import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -58,6 +42,16 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; +import java.util.List; + +import static com.example.mate.domain.match.entity.MatchStatus.SCHEDULED; +import static com.example.mate.domain.mate.entity.Status.CLOSED; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + @SpringBootTest @AutoConfigureMockMvc(addFilters = false) @Transactional @@ -438,4 +432,49 @@ void delete_member_success() throws Exception { .andExpect(status().isNoContent()); } } + + @Nested + @DisplayName("회원 로그인") + class LoginMember { + + @Test + @DisplayName("회원 로그인 성공") + void login_member_success() throws Exception { + // given + MemberLoginRequest request = MemberLoginRequest.builder() + .email("tester@example.com") + .build(); + + // when & then + mockMvc.perform(post("/api/members/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status").value("SUCCESS")) + .andExpect(jsonPath("$.data.memberId").value("1")) + .andExpect(jsonPath("$.data.nickname").value("tester")) + .andExpect(jsonPath("$.data.teamId").value("1")) + .andExpect(jsonPath("$.data.gender").value("남자")) + .andExpect(jsonPath("$.data.age").value("20")) + .andDo(print()); + } + + @Test + @DisplayName("회원 로그인 실패 - 존재하지 않는 이메일") + void login_member_fail_non_exists_email() throws Exception { + // given + MemberLoginRequest request = MemberLoginRequest.builder() + .email("test10000@example.com") + .build(); + + // when & then + mockMvc.perform(post("/api/members/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andDo(print()) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.status").value("ERROR")) + .andExpect(jsonPath("$.message").value("해당 이메일의 회원 정보를 찾을 수 없습니다.")); + } + } } \ No newline at end of file diff --git a/src/test/java/com/example/mate/domain/member/service/MemberServiceTest.java b/src/test/java/com/example/mate/domain/member/service/MemberServiceTest.java index de614c98..36667896 100644 --- a/src/test/java/com/example/mate/domain/member/service/MemberServiceTest.java +++ b/src/test/java/com/example/mate/domain/member/service/MemberServiceTest.java @@ -2,6 +2,7 @@ import com.example.mate.common.error.CustomException; import com.example.mate.common.error.ErrorCode; +import com.example.mate.common.security.util.JwtUtil; import com.example.mate.domain.constant.Gender; import com.example.mate.domain.constant.Rating; import com.example.mate.domain.constant.TeamInfo; @@ -17,7 +18,9 @@ import com.example.mate.domain.mate.repository.VisitPartRepository; import com.example.mate.domain.member.dto.request.JoinRequest; import com.example.mate.domain.member.dto.request.MemberInfoUpdateRequest; +import com.example.mate.domain.member.dto.request.MemberLoginRequest; import com.example.mate.domain.member.dto.response.JoinResponse; +import com.example.mate.domain.member.dto.response.MemberLoginResponse; import com.example.mate.domain.member.dto.response.MemberProfileResponse; import com.example.mate.domain.member.dto.response.MyProfileResponse; import com.example.mate.domain.member.entity.Follow; @@ -71,6 +74,8 @@ class MemberServiceTest { @Mock private FileService fileService; + @Mock + private JwtUtil jwtUtil; private Member member; private Member member2; @@ -474,4 +479,51 @@ void delete_member_fail_not_exists_member() { verify(memberRepository).findById(memberId); } } + + @Nested + @DisplayName("회원 로그인") + class LoginMember { + + @Test + @DisplayName("회원 로그인 성공") + void login_member_success() { + // given + String email = "test@example.com"; + MemberLoginRequest request = MemberLoginRequest.builder() + .email("test@example.com") + .build(); + + given(memberRepository.findByEmail(email)).willReturn(Optional.of(member)); + + // when + MemberLoginResponse response = memberService.loginByEmail(request); + + // then + assertThat(response).isNotNull(); + assertThat(response.getNickname()).isEqualTo("tester"); + assertThat(response.getAge()).isEqualTo(30); + assertThat(response.getTeamId()).isEqualTo(1L); + + verify(memberRepository).findByEmail(member.getEmail()); + } + + @Test + @DisplayName("회원 로그인 실패 - 존재하지 않는 이메일") + void login_member_fail_non_exists_email() { + // given + String email = "test10@example.com"; + MemberLoginRequest request = MemberLoginRequest.builder() + .email("test10@example.com") + .build(); + + given(memberRepository.findByEmail(email)).willReturn(Optional.empty()); + + // when & then + assertThatThrownBy(() -> memberService.loginByEmail(request)) + .isInstanceOf(CustomException.class) + .hasMessage(ErrorCode.MEMBER_NOT_FOUND_BY_EMAIL.getMessage()); + + verify(memberRepository).findByEmail(email); + } + } } \ No newline at end of file