diff --git a/backend/memetory/build.gradle b/backend/memetory/build.gradle index 7eae8f68..93d529c4 100644 --- a/backend/memetory/build.gradle +++ b/backend/memetory/build.gradle @@ -40,6 +40,11 @@ dependencies { // Swagger 적용 implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' + + // test에 lombok 추가 + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.security:spring-security-test' } tasks.named('test') { diff --git a/backend/memetory/src/main/java/com/example/memetory/domain/member/controller/MemberApi.java b/backend/memetory/src/main/java/com/example/memetory/domain/member/controller/MemberApi.java index 922de8ae..b1622736 100644 --- a/backend/memetory/src/main/java/com/example/memetory/domain/member/controller/MemberApi.java +++ b/backend/memetory/src/main/java/com/example/memetory/domain/member/controller/MemberApi.java @@ -1,31 +1,35 @@ package com.example.memetory.domain.member.controller; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + import com.example.memetory.domain.member.dto.MemberSignUpRequest; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; +import jakarta.servlet.http.HttpServletResponse; @Tag(name = "Member") public interface MemberApi { - @Operation( - summary = "회원가입", - description = "첫 소셜로그인 후 추가 정보 기입", - security = {@SecurityRequirement(name = "access_token")} - ) - @ApiResponses(value = { - @ApiResponse( - responseCode = "200", - description = "회원가입 성공!" - ) - }) - ResponseEntity register( - MemberSignUpRequest memberSignUpRequest, - @Parameter(hidden = true) String email - ); + @Operation( + summary = "회원가입", + description = "첫 소셜로그인 후 추가 정보 기입", + security = {@SecurityRequirement(name = "access_token")} + ) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "회원가입 성공!" + ) + }) + ResponseEntity register( + HttpServletResponse response, + MemberSignUpRequest memberSignUpRequest, + @Parameter(hidden = true) String email + ); } diff --git a/backend/memetory/src/main/java/com/example/memetory/domain/member/controller/MemberController.java b/backend/memetory/src/main/java/com/example/memetory/domain/member/controller/MemberController.java index a5798255..92a03b11 100644 --- a/backend/memetory/src/main/java/com/example/memetory/domain/member/controller/MemberController.java +++ b/backend/memetory/src/main/java/com/example/memetory/domain/member/controller/MemberController.java @@ -10,23 +10,32 @@ import com.example.memetory.domain.member.dto.MemberSignUpRequest; import com.example.memetory.domain.member.service.MemberService; import com.example.memetory.global.annotation.LoginMemberEmail; +import com.example.memetory.global.security.jwt.refresh.service.RefreshTokenService; +import com.example.memetory.global.security.jwt.service.JwtService; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; @RestController @RequiredArgsConstructor public class MemberController implements MemberApi { + private final MemberService memberService; + private final JwtService jwtService; + private final RefreshTokenService refreshTokenService; - private final MemberService memberService; + @PostMapping("/sign-up") + @Override + public ResponseEntity register( + HttpServletResponse response, @RequestBody MemberSignUpRequest memberSignUpRequest, + @LoginMemberEmail String email) { + MemberServiceDto memberServiceDto = memberSignUpRequest.toServiceDto(email); - @PostMapping("/sign-up") - @Override - public ResponseEntity register(@RequestBody MemberSignUpRequest memberSignUpRequest, - @LoginMemberEmail String email) { - MemberServiceDto memberServiceDto = memberSignUpRequest.toServiceDto(email); + memberService.register(memberServiceDto); - memberService.register(memberServiceDto); + String refreshToken = jwtService.createRefreshToken(); + jwtService.setRefreshTokenHeader(response, refreshToken); + refreshTokenService.updateToken(email, refreshToken); - return ResponseEntity.status(HttpStatus.OK).build(); - } + return ResponseEntity.status(HttpStatus.OK).build(); + } } diff --git a/backend/memetory/src/main/java/com/example/memetory/domain/member/dto/MemberSignUpRequest.java b/backend/memetory/src/main/java/com/example/memetory/domain/member/dto/MemberSignUpRequest.java index 946dda25..647c892d 100644 --- a/backend/memetory/src/main/java/com/example/memetory/domain/member/dto/MemberSignUpRequest.java +++ b/backend/memetory/src/main/java/com/example/memetory/domain/member/dto/MemberSignUpRequest.java @@ -2,9 +2,11 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +@AllArgsConstructor @NoArgsConstructor(access = AccessLevel.PRIVATE) @Getter @Schema(description = "회원 가입 포맷") diff --git a/backend/memetory/src/main/java/com/example/memetory/domain/member/service/MemberService.java b/backend/memetory/src/main/java/com/example/memetory/domain/member/service/MemberService.java index cf938a35..83642344 100644 --- a/backend/memetory/src/main/java/com/example/memetory/domain/member/service/MemberService.java +++ b/backend/memetory/src/main/java/com/example/memetory/domain/member/service/MemberService.java @@ -4,17 +4,10 @@ import org.springframework.transaction.annotation.Transactional; import com.example.memetory.domain.member.dto.MemberServiceDto; -import com.example.memetory.domain.member.dto.MemberSignUpRequest; import com.example.memetory.domain.member.entity.Member; import com.example.memetory.domain.member.exception.NotFoundMemberException; import com.example.memetory.domain.member.repository.MemberRepository; -import com.example.memetory.global.security.jwt.exception.NotFoundEmailException; -import com.example.memetory.global.security.jwt.exception.NotFoundTokenException; -import com.example.memetory.global.security.jwt.refresh.service.RefreshTokenService; -import com.example.memetory.global.security.jwt.service.JwtService; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -22,28 +15,13 @@ @RequiredArgsConstructor @Slf4j public class MemberService { - private final MemberRepository memberRepository; - private final JwtService jwtService; - private final RefreshTokenService refreshTokenService; - private final HttpServletRequest request; - private final HttpServletResponse response; @Transactional public void register(MemberServiceDto memberServiceDto) { Member member = findByEmail(memberServiceDto.getEmail()); member.register(memberServiceDto); - - String refreshToken = jwtService.createRefreshToken(); - - jwtService.setRefreshTokenHeader(response, refreshToken); - refreshTokenService.updateToken(member.getEmail(), refreshToken); - } - - public String getMemberByEmail() { - String accessToken = jwtService.extractAccessToken(request).orElseThrow(NotFoundTokenException::new); - return jwtService.extractEmail(accessToken).orElseThrow(NotFoundEmailException::new); } @Transactional(readOnly = true) diff --git a/backend/memetory/src/main/java/com/example/memetory/global/resolver/LoginMemberArgumentResolver.java b/backend/memetory/src/main/java/com/example/memetory/global/resolver/LoginMemberArgumentResolver.java index 9e43b3e1..f96466f9 100644 --- a/backend/memetory/src/main/java/com/example/memetory/global/resolver/LoginMemberArgumentResolver.java +++ b/backend/memetory/src/main/java/com/example/memetory/global/resolver/LoginMemberArgumentResolver.java @@ -7,9 +7,10 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -import com.example.memetory.domain.member.service.MemberService; import com.example.memetory.global.annotation.LoginMemberEmail; +import com.example.memetory.global.security.jwt.service.JwtService; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -18,9 +19,10 @@ @Slf4j public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver { - private final MemberService memberService; + private final JwtService jwtService; @Override + public boolean supportsParameter(MethodParameter methodParameter) { return methodParameter.hasParameterAnnotation(LoginMemberEmail.class); } @@ -28,6 +30,7 @@ public boolean supportsParameter(MethodParameter methodParameter) { @Override public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) { - return memberService.getMemberByEmail(); + HttpServletRequest request = (HttpServletRequest)nativeWebRequest.getNativeRequest(); + return jwtService.getEmail(request); } } \ No newline at end of file diff --git a/backend/memetory/src/main/java/com/example/memetory/global/security/jwt/service/JwtService.java b/backend/memetory/src/main/java/com/example/memetory/global/security/jwt/service/JwtService.java index 09ef4585..35ed9948 100644 --- a/backend/memetory/src/main/java/com/example/memetory/global/security/jwt/service/JwtService.java +++ b/backend/memetory/src/main/java/com/example/memetory/global/security/jwt/service/JwtService.java @@ -3,8 +3,8 @@ import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.example.memetory.domain.member.repository.MemberRepository; -import com.example.memetory.global.security.jwt.refresh.domain.RefreshToken; -import com.example.memetory.global.security.jwt.refresh.repository.RefreshTokenRepository; +import com.example.memetory.global.security.jwt.exception.NotFoundEmailException; +import com.example.memetory.global.security.jwt.exception.NotFoundTokenException; import com.example.memetory.global.security.jwt.refresh.service.RefreshTokenService; import jakarta.servlet.http.HttpServletRequest; @@ -15,7 +15,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import java.util.Date; import java.util.Optional; @@ -112,6 +111,11 @@ public Optional extractEmail(String accessToken) { } } + public String getEmail(HttpServletRequest request) { + String accessToken = this.extractAccessToken(request).orElseThrow(NotFoundTokenException::new); + return this.extractEmail(accessToken).orElseThrow(NotFoundEmailException::new); + } + // 헤더에 accessToken 설정 public void setAccessTokenHeader(HttpServletResponse response, String accessToken) { response.setHeader(accessHeader,BEARER + accessToken); diff --git a/backend/memetory/src/main/java/com/example/memetory/global/security/oauth/handler/OAuth2LoginSuccessHandler.java b/backend/memetory/src/main/java/com/example/memetory/global/security/oauth/handler/OAuth2LoginSuccessHandler.java index 424ae231..d3d95781 100644 --- a/backend/memetory/src/main/java/com/example/memetory/global/security/oauth/handler/OAuth2LoginSuccessHandler.java +++ b/backend/memetory/src/main/java/com/example/memetory/global/security/oauth/handler/OAuth2LoginSuccessHandler.java @@ -36,7 +36,7 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo if (oAuth2User.getRole() == Role.GUEST) { String accessToken = jwtService.createAccessToken(oAuth2User.getEmail()); response.addHeader(jwtService.getAccessHeader(), "Bearer " + accessToken); - // response.sendRedirect("oauth2/sign-up"); // 프론트의 회원가입 추가 정보 입력 폼으로 리다이렉트 + // response.sendRedirect("/sign-up"); // 프론트의 회원가입 추가 정보 입력 폼으로 리다이렉트 jwtService.setAccessTokenHeader(response, accessToken); diff --git a/backend/memetory/src/test/java/com/example/memetory/config/SecurityTestConfig.java b/backend/memetory/src/test/java/com/example/memetory/config/SecurityTestConfig.java new file mode 100644 index 00000000..abc1e18a --- /dev/null +++ b/backend/memetory/src/test/java/com/example/memetory/config/SecurityTestConfig.java @@ -0,0 +1,52 @@ +package com.example.memetory.config; + +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.factory.PasswordEncoderFactories; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.logout.LogoutFilter; + +import com.example.memetory.domain.member.repository.MemberRepository; +import com.example.memetory.global.security.jwt.filter.JwtAuthenticationProcessingFilter; +import com.example.memetory.global.security.jwt.refresh.service.RefreshTokenService; +import com.example.memetory.global.security.jwt.service.JwtService; + +import lombok.RequiredArgsConstructor; + +@TestConfiguration +@RequiredArgsConstructor +public class SecurityTestConfig { + private final JwtService jwtService; + private final MemberRepository memberRepository; + private final RefreshTokenService refreshTokenService; + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.formLogin(AbstractHttpConfigurer::disable) // 기본 제공하는 로그인 Form 사용 X + .httpBasic(AbstractHttpConfigurer::disable) // Bearer방식이기 때문에 httpBasic 사용 X + .csrf(AbstractHttpConfigurer::disable) //csrf 보안 사용 X + .sessionManagement((sessionManagement) -> // 세션은 사용하지 않기 때문에 stateless 설정 + sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests(authorizeRequests // 개발을 진행하기 위해 일단 모든 url 허용 + -> authorizeRequests.anyRequest().permitAll()); + + http.addFilterAfter(jwtAuthenticationProcessingFilter(), LogoutFilter.class); + + return http.build(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return PasswordEncoderFactories.createDelegatingPasswordEncoder(); + } + + @Bean + public JwtAuthenticationProcessingFilter jwtAuthenticationProcessingFilter() { + return new JwtAuthenticationProcessingFilter(jwtService, memberRepository, refreshTokenService); + } +} diff --git a/backend/memetory/src/test/java/com/example/memetory/domain/member/MemberFixture.java b/backend/memetory/src/test/java/com/example/memetory/domain/member/MemberFixture.java new file mode 100644 index 00000000..d4fb3d18 --- /dev/null +++ b/backend/memetory/src/test/java/com/example/memetory/domain/member/MemberFixture.java @@ -0,0 +1,35 @@ +package com.example.memetory.domain.member; + +import com.example.memetory.domain.member.dto.MemberServiceDto; +import com.example.memetory.domain.member.entity.Member; +import com.example.memetory.domain.member.entity.Role; +import com.example.memetory.domain.member.entity.SocialType; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class MemberFixture { + public final static Member MEMBER = Member.builder() + .email("junrain@ourservice.com") + .role(Role.USER) + .imageUrl("imageUrl") + .nickname("이준우") + .socialType(SocialType.GOOGLE) + .socialId("-1") + .build(); + + public final static Member GUEST_MEMBER = Member.builder() + .email("junrain@ourservice.com") + .role(Role.GUEST) + .imageUrl("imageUrl") + .nickname("이준우") + .socialType(SocialType.GOOGLE) + .socialId("-1") + .build(); + + public final static MemberServiceDto MEMBER_SERVICE_DTO = MemberServiceDto.builder() + .imageUrl("imageUrl") + .nickname("junRain") + .email("junrain@ourservice.com") + .build(); +} diff --git a/backend/memetory/src/test/java/com/example/memetory/domain/member/controller/MemberControllerTest.java b/backend/memetory/src/test/java/com/example/memetory/domain/member/controller/MemberControllerTest.java new file mode 100644 index 00000000..762a13ec --- /dev/null +++ b/backend/memetory/src/test/java/com/example/memetory/domain/member/controller/MemberControllerTest.java @@ -0,0 +1,90 @@ +package com.example.memetory.domain.member.controller; + +import static com.example.memetory.domain.member.MemberFixture.*; +import static org.mockito.BDDMockito.*; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import java.util.Date; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.example.memetory.config.SecurityTestConfig; +import com.example.memetory.domain.member.dto.MemberSignUpRequest; +import com.example.memetory.domain.member.repository.MemberRepository; +import com.example.memetory.domain.member.service.MemberService; +import com.example.memetory.global.security.jwt.refresh.service.RefreshTokenService; +import com.example.memetory.global.security.jwt.service.JwtService; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +@DisplayName("Member 컨트롤러 테스트의 ") +@WebMvcTest(MemberController.class) +@Import(SecurityTestConfig.class) +public class MemberControllerTest { + + @Autowired + MockMvc mockMvc; + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private JwtService jwtService; + @MockBean + private MemberService memberService; + @MockBean + private RefreshTokenService refreshTokenService; + @MockBean + private MemberRepository memberRepository; + + @Value("${jwt.secretKey}") + private String secretKey; + private String authorization_jwt; + + @BeforeEach + void setUp() { + Date now = new Date(); + authorization_jwt = JWT.create() + .withSubject("AccessToken") + .withExpiresAt(new Date(now.getTime() + 180000)) + .withClaim("email", GUEST_MEMBER.getId()) + .sign(Algorithm.HMAC512(secretKey)); + } + + // 잘 된 테스트인지는 아직 의문 + @Test + @DisplayName("회원가입이 완료되었는가") + void 회원가입() throws Exception { + // given -> 결과에 대한 객체, Member 객체 저장할 필요 존재 + given(memberRepository.findByEmail(GUEST_MEMBER.getEmail())).willReturn(Optional.ofNullable(GUEST_MEMBER)); + + // when + final ResultActions perform = mockMvc.perform( + post("/sign-up") + .contentType(MediaType.APPLICATION_JSON) + .content(toRequestBody(new MemberSignUpRequest("Memetory"))) + .header("Authorization", "Bearer " + authorization_jwt) + ); + + // then + perform.andExpect(status().isOk()); + } + + protected String toRequestBody(Object value) throws JsonProcessingException { + return objectMapper.writeValueAsString(value); + } +} diff --git a/backend/memetory/src/test/java/com/example/memetory/domain/member/repository/MemberRepositoryTest.java b/backend/memetory/src/test/java/com/example/memetory/domain/member/repository/MemberRepositoryTest.java new file mode 100644 index 00000000..26b1b2b4 --- /dev/null +++ b/backend/memetory/src/test/java/com/example/memetory/domain/member/repository/MemberRepositoryTest.java @@ -0,0 +1,52 @@ +package com.example.memetory.domain.member.repository; + +import static com.example.memetory.domain.member.MemberFixture.*; +import static org.assertj.core.api.AssertionsForClassTypes.*; + +import java.util.Optional; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; + +import com.example.memetory.domain.member.entity.Member; +import com.example.memetory.global.config.JpaAuditingConfig; + +@DataJpaTest +@DisplayName("member 레포지토리 테스트의 ") +@Import(JpaAuditingConfig.class) +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +public class MemberRepositoryTest { + @Autowired + private MemberRepository memberRepository; + + @Test + @DisplayName("이메일로 멤버 찾기") + public void 이메일로_Member_찾기() { + // given -> 멤버 저장하기 + Member savedMember = memberRepository.save(MEMBER); + + // when 멤버 찾기 + Optional findMember = memberRepository.findByEmail(savedMember.getEmail()); + + // then 확인하기 + assertThat(savedMember).isEqualTo(findMember.get()); + } + + @Test + @DisplayName("SocialType과 SocialId로 멤버 찾기") + public void SocialType과_SocialId로_Member_찾기() { + // given -> 멤버 저장하기 + Member savedMember = memberRepository.save(MEMBER); + + // when 멤버 찾기 + Optional findMember = memberRepository + .findBySocialTypeAndSocialId(savedMember.getSocialType(), savedMember.getSocialId()); + + // then 확인하기 + assertThat(savedMember).isEqualTo(findMember.get()); + } +} diff --git a/backend/memetory/src/test/java/com/example/memetory/domain/member/service/MemberServiceTest.java b/backend/memetory/src/test/java/com/example/memetory/domain/member/service/MemberServiceTest.java new file mode 100644 index 00000000..3a10ade7 --- /dev/null +++ b/backend/memetory/src/test/java/com/example/memetory/domain/member/service/MemberServiceTest.java @@ -0,0 +1,71 @@ +package com.example.memetory.domain.member.service; + +import static com.example.memetory.domain.member.MemberFixture.*; +import static org.assertj.core.api.Assertions.*; + +import java.util.Optional; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; + +import com.example.memetory.domain.member.entity.Member; +import com.example.memetory.domain.member.entity.Role; +import com.example.memetory.domain.member.repository.MemberRepository; +import com.example.memetory.global.security.jwt.service.JwtService; + +@DisplayName("memberService의 ") +@Transactional +@SpringBootTest +public class MemberServiceTest { + @Autowired + private MemberService memberService; + @Autowired + private JwtService jwtService; + @Autowired + private MemberRepository memberRepository; + + @Test + @DisplayName("회원가입이 잘 진행 되는가?") + void 회원가입() { + // given 멤버 저장 + Member savedMember = memberRepository.save(GUEST_MEMBER); + + // when 실행 + memberService.register(MEMBER_SERVICE_DTO); + + // then 확인 ROLE과 닉네임이 잘 변경 됐는지 확인 + Optional updatedMember = memberRepository.findByEmail(GUEST_MEMBER.getEmail()); + assertThat(MEMBER_SERVICE_DTO.getNickname()).isEqualTo(updatedMember.get().getNickname()); + assertThat(Role.USER).isEqualTo(updatedMember.get().getRole()); + } + + @Test + @DisplayName("이메일을 통해서 멤버 가져오기") + void 이메일을_통해서_Member_불러오기() { + // given 멤버 저장 + Member savedMember = memberRepository.save(MEMBER); + + // when 실행 + Member findMember = memberService.findByEmail(savedMember.getEmail()); + + // then + assertThat(findMember.getId()).isEqualTo(savedMember.getId()); + + } + + @Test + @DisplayName("ID를 통해서 멤버 가져오기") + void ID를_통해서_Member_불러오기() { + // given 멤버 저장 + Member savedMember = memberRepository.save(MEMBER); + + // when 실행 + Member findMember = memberService.findById(savedMember.getId()); + + // then + assertThat(findMember.getId()).isEqualTo(savedMember.getId()); + } +}