diff --git a/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/dto/AnswerCreateRequest.java b/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/dto/AnswerCreateRequest.java index 73178181..fd03c520 100644 --- a/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/dto/AnswerCreateRequest.java +++ b/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/dto/AnswerCreateRequest.java @@ -37,7 +37,7 @@ public AnswerCreateRequest(Long questionId, String content, public static AnswerCreateRequest of(Long questionId, String content, Boolean profileOnOff, String linkAttachments, String musicName, String musicSinger, String musicAudioUrl, String imageUrl, boolean updateImage) { - return new AnswerCreateRequest(questionId, content, profileOnOff, linkAttachments, + return new AnswerCreateRequest(questionId, content, profileOnOff, linkAttachments, musicName, musicSinger, musicAudioUrl, imageUrl, updateImage); } } \ No newline at end of file diff --git a/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/dto/AnswerDetailResponse.java b/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/dto/AnswerDetailResponse.java index 0c7be46f..209f8350 100644 --- a/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/dto/AnswerDetailResponse.java +++ b/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/dto/AnswerDetailResponse.java @@ -13,7 +13,7 @@ public class AnswerDetailResponse { private String questionContent; private Long memberId; private String content; - private String memberNickname; + private String nickname; private Boolean profileOnOff; private String linkAttachments; private String musicName; @@ -24,7 +24,7 @@ public class AnswerDetailResponse { public AnswerDetailResponse(Long answerId, Long questionId, String questionContent, Long memberId, - String content, String memberNickname, Boolean profileOnOff, + String content, String nickname, Boolean profileOnOff, String linkAttachments, String musicName, String musicSinger, String musicAudioUrl, String imageUrl, LocalDateTime createdDate) { @@ -34,7 +34,7 @@ public AnswerDetailResponse(Long answerId, Long questionId, String questionConte this.questionContent = questionContent; this.memberId = memberId; this.content = content; - this.memberNickname = memberNickname; + this.nickname = nickname; this.profileOnOff = profileOnOff; this.linkAttachments = linkAttachments; this.musicName = musicName; @@ -45,10 +45,10 @@ public AnswerDetailResponse(Long answerId, Long questionId, String questionConte } public static AnswerDetailResponse of(Long answerId, Long questionId, String questionContent, Long memberId, - String content, String memberNickname, Boolean profileOnOff, + String content, String nickname, Boolean profileOnOff, String linkAttachments, String musicName, String musicSinger, String musicAudioUrl, String imageUrl, LocalDateTime createdDate) { - return new AnswerDetailResponse(answerId, questionId, questionContent, memberId, content, memberNickname, + return new AnswerDetailResponse(answerId, questionId, questionContent, memberId, content, nickname, profileOnOff, linkAttachments, musicName, musicSinger, musicAudioUrl, imageUrl, createdDate); diff --git a/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/entity/Answer.java b/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/entity/Answer.java index 8d13944b..a790be8c 100644 --- a/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/entity/Answer.java +++ b/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/entity/Answer.java @@ -37,13 +37,15 @@ public class Answer { @OnDelete(action = OnDeleteAction.CASCADE) private Member member; - @Column(name = "image_file") private String imageFile; // 이미지 파일 경로를 저장하는 리스트 @Column(name = "content", columnDefinition = "TEXT", nullable = false) private String content; + @Column(name = "nickname") + private String nickname; + @OneToOne(mappedBy = "answer", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) private Music music; @@ -65,10 +67,10 @@ public class Answer { @Column(name = "profile_on_off", nullable = false) private boolean profileOnOff; - public static Answer of(Long id, Question question, Member member, String content, + public static Answer of(Long id, Question question, Member member, String content, String nickname, String imageFile, Music music, String linkAttachments, String imageUrl, LocalDateTime createdDate, ReactionCount reactionCount, boolean profileOnOff) { - return new Answer(id, question, member, imageFile, content, music, linkAttachments, imageUrl, createdDate, null, reactionCount, profileOnOff); + return new Answer(id, question, member, imageFile, content, nickname, music, linkAttachments, imageUrl, createdDate, null, reactionCount, profileOnOff); } } diff --git a/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/repository/AnswerMapper.java b/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/repository/AnswerMapper.java index 73bafbb7..69960cc8 100644 --- a/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/repository/AnswerMapper.java +++ b/baebae-BE/src/main/java/com/web/baebaeBE/domain/answer/repository/AnswerMapper.java @@ -24,11 +24,14 @@ public Answer toEntity(AnswerCreateRequest request, Question question, Member me .musicAudioUrl(request.getMusicAudioUrl()) .build(); + String senderNickname = question.getSender().getNickname(); + // Answer 엔티티 생성 및 Music 설정 Answer answer = Answer.builder() .question(question) .member(member) .content(request.getContent()) + .nickname(senderNickname) .linkAttachments(request.getLinkAttachments()) .profileOnOff(request.getProfileOnOff()) .createdDate(LocalDateTime.now()) @@ -46,13 +49,14 @@ public AnswerDetailResponse toDomain(Answer answer) { Member member = answer.getMember(); Question question = answer.getQuestion(); + return AnswerDetailResponse.of( answer.getId(), question.getId(), question.getContent(), member.getId(), answer.getContent(), - member.getNickname(), + answer.getNickname(), answer.isProfileOnOff(), answer.getLinkAttachments(), music != null ? music.getMusicName() : null, diff --git a/baebae-BE/src/test/java/com/web/baebaeBE/integration/answer/AnswerTest.java b/baebae-BE/src/test/java/com/web/baebaeBE/integration/answer/AnswerTest.java index febcb817..13d06e2e 100644 --- a/baebae-BE/src/test/java/com/web/baebaeBE/integration/answer/AnswerTest.java +++ b/baebae-BE/src/test/java/com/web/baebaeBE/integration/answer/AnswerTest.java @@ -53,13 +53,13 @@ public class AnswerTest { @Autowired private MockMvc mockMvc; - @Autowired + @MockBean private MemberRepository memberRepository; - @Autowired + @MockBean private QuestionRepository questionRepository; - @Autowired + @MockBean private QuestionJpaRepository questionJpaRepository; @MockBean @@ -80,20 +80,29 @@ public class AnswerTest { @BeforeEach void setup() { - testMember = memberRepository.save(Member.builder() + // Mock 객체 초기화 + testMember = Member.builder() .email("test@gmail.com") .nickname("장지효") .memberType(MemberType.KAKAO) .refreshToken("null") - .build()); + .build(); - testReceiver = memberRepository.save(Member.builder() + testReceiver = Member.builder() .email("test@gmail2.com") .nickname("장지효2") .memberType(MemberType.KAKAO) .refreshToken("null") - .build()); + .build(); + + // memberRepository.save() 메서드를 목킹하여 호출된 객체를 반환하도록 설정 + when(memberRepository.save(any(Member.class))).thenAnswer(invocation -> invocation.getArgument(0)); + // testMember와 testReceiver를 저장 + testMember = memberRepository.save(testMember); + testReceiver = memberRepository.save(testReceiver); + + // 토큰 생성 및 업데이트 refreshToken = tokenProvider.generateToken(testMember, Duration.ofDays(14)); testMember.updateRefreshToken(refreshToken); memberRepository.save(testMember); @@ -102,41 +111,43 @@ void setup() { testReceiver.updateRefreshToken(refreshToken); memberRepository.save(testReceiver); - testQuestion = questionRepository.save(new Question(null, testMember, testReceiver,"이것은 질문입니다.", "장지효", true, LocalDateTime.now(), false)); + // memberRepository.save() 메서드를 목킹하여 호출된 객체를 반환하도록 설정 + when(questionRepository.save(any(Question.class))).thenAnswer(invocation -> invocation.getArgument(0)); + + // testQuestion 저장 + testQuestion = questionRepository.save(new Question(null, testMember, testReceiver, "이것은 질문입니다.", "장지효", true, LocalDateTime.now(), false)); } @AfterEach void tearDown() { questionJpaRepository.deleteAll(); - Optional member = memberRepository.findByEmail("test@gmail.com"); - member.ifPresent(memberRepository::delete); + memberRepository.deleteAll(); } @Test @DisplayName("답변 생성 테스트(): 답변을 생성한다.") public void createAnswerTest() throws Exception { AnswerCreateRequest createRequest = new AnswerCreateRequest( - testQuestion.getId(), "이것은 답변입니다.", "장지효", true, "https://link.com", + testQuestion.getId(), "이것은 답변입니다.", true, "https://link.com", "노래 제목", "가수 이름", "https://audio.url", "https://image.url", true ); MockMultipartFile imageFile = new MockMultipartFile("imageFile", "image.jpg", MediaType.IMAGE_JPEG_VALUE, "image content".getBytes()); MockMultipartFile requestFile = new MockMultipartFile("request", "", MediaType.APPLICATION_JSON_VALUE, objectMapper.writeValueAsBytes(createRequest)); - when(answerService.createAnswer(any(AnswerCreateRequest.class), eq(testMember.getId()), any(MockMultipartFile.class))) + when(answerService.createAnswer(any(AnswerCreateRequest.class), eq(1L), any(MockMultipartFile.class))) .thenReturn(new AnswerDetailResponse( - 1L, testQuestion.getId(), testQuestion.getContent(), testMember.getId(), "이것은 답변입니다.", - testMember.getNickname(), "장지효", true, "https://link.com", "노래 제목", "가수 이름", "https://audio.url", + 1L, testQuestion.getId(), testQuestion.getContent(),1L, "이것은 답변입니다.", + testMember.getNickname(), true, "https://link.com", "노래 제목", "가수 이름", "https://audio.url", "https://image.url", LocalDateTime.now() )); - mockMvc.perform(MockMvcRequestBuilders.multipart("/api/answers/{memberId}", testMember.getId()) + mockMvc.perform(MockMvcRequestBuilders.multipart("/api/answers/{memberId}", 1L) .file(imageFile) .file(requestFile) .header("Authorization", "Bearer " + refreshToken) .contentType(MediaType.MULTIPART_FORM_DATA)) .andExpect(status().isOk()) .andExpect(jsonPath("$.content").value("이것은 답변입니다.")) - .andExpect(jsonPath("$.nickname").value("장지효")) .andExpect(jsonPath("$.profileOnOff").value(true)) .andExpect(jsonPath("$.linkAttachments").value("https://link.com")) .andExpect(jsonPath("$.musicName").value("노래 제목")) @@ -152,16 +163,16 @@ public void createAnswerTest() throws Exception { public void getAllAnswersTest() throws Exception { AnswerDetailResponse answerDetailResponse = new AnswerDetailResponse( 1L, testQuestion.getId(), testQuestion.getContent(), testMember.getId(), - "이것은 답변입니다.", testMember.getNickname(), "장지효", true, "https://link.com", + "이것은 답변입니다.", testMember.getNickname(), true, "https://link.com", "노래 제목", "가수 이름", "https://audio.url", "https://image.url", LocalDateTime.now() ); List answerDetailResponseList = List.of(answerDetailResponse); Page answerDetailResponsePage = new PageImpl<>(answerDetailResponseList, Pageable.unpaged(), 1); - when(answerService.getAllAnswers(eq(testMember.getId()), any(Long.class), any(Pageable.class))) + when(answerService.getAllAnswers(eq(1L), any(Long.class), any(Pageable.class))) .thenReturn(answerDetailResponsePage); - mockMvc.perform(get("/api/answers/member/{memberId}", testMember.getId()) + mockMvc.perform(get("/api/answers/member/{memberId}", 1L) .param("categoryId", "1") .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) @@ -173,7 +184,7 @@ public void getAllAnswersTest() throws Exception { public void updateAnswerTest() throws Exception { // Given AnswerCreateRequest updateRequest = new AnswerCreateRequest( - testQuestion.getId(), "이것은 수정된답변입니다.", "장지효", true, "https://link.com", + testQuestion.getId(), "이것은 수정된답변입니다.", true, "https://link.com", "노래 제목", "가수 이름", "https://audio.url", "https://image.url", true ); MockMultipartFile imageFile = new MockMultipartFile("imageFile", "image.jpg", MediaType.IMAGE_JPEG_VALUE, "image content".getBytes()); @@ -181,7 +192,7 @@ public void updateAnswerTest() throws Exception { AnswerDetailResponse answerDetailResponse = new AnswerDetailResponse( 1L, testQuestion.getId(), testQuestion.getContent(), testMember.getId(), "이것은 수정된답변입니다.", - testMember.getNickname(), "장지효", true, "https://link.com", "노래 제목", "가수 이름", "https://audio.url", + testMember.getNickname(), true, "https://link.com", "노래 제목", "가수 이름", "https://audio.url", "https://image.url", LocalDateTime.now() ); @@ -198,7 +209,6 @@ public void updateAnswerTest() throws Exception { .andDo(print()) // 응답 내용 출력 .andExpect(status().isOk()) .andExpect(jsonPath("$.content").value("이것은 수정된답변입니다.")) - .andExpect(jsonPath("$.nickname").value("장지효")) .andExpect(jsonPath("$.profileOnOff").value(true)) .andExpect(jsonPath("$.linkAttachments").value("https://link.com")) .andExpect(jsonPath("$.musicName").value("노래 제목")) @@ -223,7 +233,7 @@ public void hasReactedTest() throws Exception { when(answerService.hasReacted(eq(1L), eq(testMember.getId()))).thenReturn(Map.of()); mockMvc.perform(get("/api/answers/{answerId}/reacted", 1L) - .param("memberId", String.valueOf(testMember.getId())) + .param("memberId", String.valueOf(1L)) .header("Authorization", "Bearer " + refreshToken) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) diff --git a/baebae-BE/src/test/java/com/web/baebaeBE/integration/manage/member/ManageMemberTest.java b/baebae-BE/src/test/java/com/web/baebaeBE/integration/manage/member/ManageMemberTest.java index 7983f221..06bed1fc 100644 --- a/baebae-BE/src/test/java/com/web/baebaeBE/integration/manage/member/ManageMemberTest.java +++ b/baebae-BE/src/test/java/com/web/baebaeBE/integration/manage/member/ManageMemberTest.java @@ -2,6 +2,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.web.baebaeBE.domain.fcm.dto.FcmRequest; +import com.web.baebaeBE.domain.fcm.entity.FcmToken; +import com.web.baebaeBE.domain.fcm.repository.FcmTokenRepository; +import com.web.baebaeBE.domain.fcm.service.FcmService; +import com.web.baebaeBE.domain.oauth2.controller.Oauth2Controller; +import com.web.baebaeBE.domain.question.dto.QuestionCreateRequest; import com.web.baebaeBE.global.jwt.JwtTokenProvider; import com.web.baebaeBE.domain.member.entity.Member; import com.web.baebaeBE.domain.member.entity.MemberType; @@ -14,6 +19,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.mock.web.MockMultipartFile; import org.springframework.security.test.context.support.WithMockUser; @@ -28,8 +34,11 @@ import java.io.OutputStream; import java.nio.file.Files; import java.time.Duration; +import java.time.LocalDateTime; import java.util.Optional; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -44,8 +53,14 @@ public class ManageMemberTest { private MockMvc mockMvc; @Autowired private JwtTokenProvider tokenProvider; - @Autowired + @MockBean private MemberRepository memberRepository; + @MockBean + private Oauth2Controller oauth2Controller; + @MockBean + private FcmService fcmService; + @MockBean + private FcmTokenRepository fcmTokenRepository; private ObjectMapper objectMapper = new ObjectMapper(); private String accessToken; private String refreshToken; @@ -54,29 +69,43 @@ public class ManageMemberTest { @BeforeEach void setup() { - testMember = memberRepository.save(Member.builder() + // 새로운 멤버 객체를 생성하지만, 실제 저장된 객체의 ID를 반환하도록 Mock 설정 + Member initialMember = Member.builder() + .email("test@gmail.com") + .nickname("김예찬") + .memberType(MemberType.KAKAO) + .refreshToken("null") + .build(); + + Member savedMember = Member.builder() + .id(1L) // Mocking된 저장된 객체의 ID 설정 .email("test@gmail.com") .nickname("김예찬") .memberType(MemberType.KAKAO) .refreshToken("null") - .build()); + .build(); + + when(memberRepository.save(any(Member.class))).thenReturn(savedMember); + when(memberRepository.findByEmail("test@gmail.com")).thenReturn(Optional.of(savedMember)); + + testMember = memberRepository.save(initialMember); // 실제 저장된 객체로 갱신 accessToken = tokenProvider.generateToken(testMember, Duration.ofDays(1)); // 임시 accessToken 생성 refreshToken = tokenProvider.generateToken(testMember, Duration.ofDays(14)); // 임시 refreshToken 생성 testMember.updateRefreshToken(refreshToken); - memberRepository.save(testMember); + + // 업데이트된 멤버 다시 저장 + when(memberRepository.save(testMember)).thenReturn(testMember); + when(memberRepository.findById(testMember.getId())).thenReturn(Optional.of(testMember)); } - //각 테스트 후마다 실행 @AfterEach void tearDown() { Optional member = memberRepository.findByEmail("test@gmail.com"); - if(member.isPresent()) - memberRepository.delete(member.get()); + member.ifPresent(value -> memberRepository.delete(value)); } - @Test @DisplayName("회원정보 조회 테스트(): 해당 회원의 상세정보를 조회한다.") public void getMemberInformation() throws Exception { @@ -86,14 +115,13 @@ public void getMemberInformation() throws Exception { mockMvc.perform(get("/api/member/{memberId}", testMember.getId()) .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer " + accessToken)) - // then + // then .andExpect(status().isOk()) .andExpect(jsonPath("$.memberId").exists()) .andExpect(jsonPath("$.email").exists()) .andExpect(jsonPath("$.nickname").exists()) .andExpect(jsonPath("$.memberType").exists()); } - @Test @DisplayName("프로필 사진 업데이트 테스트(): 회원의 프로필 사진을 업데이트한다.") public void updateProfileTest() throws Exception { @@ -133,6 +161,16 @@ public void addFcmTokenTest() throws Exception { // given FcmRequest.CreateToken tokenRequest = new FcmRequest.CreateToken("fwef094938jweSIJDe8204gaskd390GK32G9HADF0809d8708U908ud9UHD9FH4e32982hF0ODH22E"); + FcmToken fcmToken = FcmToken.builder() + .id(1L) + .token(tokenRequest.getFcmToken()) + .member(testMember) + .lastUsedTime(LocalDateTime.now()) + .build(); + + when(fcmTokenRepository.save(any(FcmToken.class))).thenReturn(fcmToken); + when(fcmService.addFcmToken(testMember.getId(), tokenRequest.getFcmToken())).thenReturn(fcmToken); + // when mockMvc.perform(post("/api/fcm/{memberId}", testMember.getId()) .contentType(MediaType.APPLICATION_JSON) diff --git a/baebae-BE/src/test/java/com/web/baebaeBE/integration/member/MemberIntegrationTest.java b/baebae-BE/src/test/java/com/web/baebaeBE/integration/member/MemberIntegrationTest.java index 3d1681d5..16640b22 100644 --- a/baebae-BE/src/test/java/com/web/baebaeBE/integration/member/MemberIntegrationTest.java +++ b/baebae-BE/src/test/java/com/web/baebaeBE/integration/member/MemberIntegrationTest.java @@ -1,12 +1,15 @@ package com.web.baebaeBE.integration.member; -import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import com.fasterxml.jackson.databind.ObjectMapper; import com.web.baebaeBE.domain.fcm.entity.FcmToken; import com.web.baebaeBE.domain.fcm.repository.FcmTokenRepository; +import com.web.baebaeBE.domain.login.dto.LoginResponse; +import com.web.baebaeBE.domain.oauth2.controller.Oauth2Controller; import com.web.baebaeBE.domain.oauth2.service.Oauth2Service; import com.web.baebaeBE.domain.login.service.LoginService; import com.web.baebaeBE.global.jwt.JwtTokenProvider; @@ -15,6 +18,7 @@ import com.web.baebaeBE.domain.member.repository.MemberRepository; import com.web.baebaeBE.domain.oauth2.dto.KakaoUserInfoDto; import com.web.baebaeBE.domain.login.dto.LoginRequest; +import jakarta.servlet.http.HttpServletRequest; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -50,14 +54,16 @@ public class MemberIntegrationTest { private RestTemplate restTemplate; @MockBean private Oauth2Service oauth2Service; - @Autowired + @MockBean private LoginService loginService; @Autowired private JwtTokenProvider tokenProvider; - @Autowired + @MockBean private MemberRepository memberRepository; - @Autowired + @MockBean private FcmTokenRepository fcmTokenRepository; + @MockBean + private Oauth2Controller oauth2Controller; private ObjectMapper objectMapper = new ObjectMapper(); private String accessToken; private String refreshToken; @@ -65,70 +71,83 @@ public class MemberIntegrationTest { //각 테스트 전마다 실행 @BeforeEach void setup() { - Member testMember = memberRepository.save(Member.builder() + Member testMember = Member.builder() + .id(1L) // ID를 명시적으로 설정 .email("test@gmail.com") .nickname("test") .memberType(MemberType.KAKAO) .refreshToken("null") - .build()); + .build(); + when(memberRepository.save(any(Member.class))).thenReturn(testMember); + when(memberRepository.findByEmail("test@gmail.com")).thenReturn(Optional.of(testMember)); + when(memberRepository.findById(1L)).thenReturn(Optional.of(testMember)); - accessToken = tokenProvider.generateToken(testMember, Duration.ofDays(1)); // 임시 accessToken 생성 - refreshToken = tokenProvider.generateToken(testMember, Duration.ofDays(14)); // 임시 refreshToken 생성 + accessToken = tokenProvider.generateToken(testMember, Duration.ofDays(1)); // 임시 accessToken 생성 + refreshToken = tokenProvider.generateToken(testMember, Duration.ofDays(14)); // 임시 refreshToken 생성 testMember.updateRefreshToken(refreshToken); - memberRepository.save(testMember); + when(memberRepository.save(testMember)).thenReturn(testMember); + + when(memberRepository.findByRefreshToken(refreshToken)).thenReturn(Optional.of(testMember)); // FcmToken 생성 및 Member에 연결 - FcmToken testFcmToken = new FcmToken(); - testFcmToken.setToken("testFcmToken"); - testFcmToken.setMember(testMember); - testFcmToken.setLastUsedTime(LocalDateTime.now()); - fcmTokenRepository.save(testFcmToken); + FcmToken testFcmToken = FcmToken.builder() + .token("testFcmToken") + .member(testMember) + .lastUsedTime(LocalDateTime.now()) + .build(); + when(fcmTokenRepository.save(any(FcmToken.class))).thenReturn(testFcmToken); + + //fcm 토큰 찾기 + when(fcmTokenRepository.findByToken("testFcmToken")).thenReturn(Optional.of(testFcmToken)); } - //각 테스트 후마다 실행 @AfterEach void tearDown() { Optional member = memberRepository.findByEmail("test@gmail.com"); - if(member.isPresent()) - memberRepository.delete(member.get()); + member.ifPresent(value -> memberRepository.delete(value)); } + @Test + @DisplayName("oAuth2 기반 로그인 테스트(): 가짜 카카오 토큰을 통해 로그인 및 회원가입 테스트한다.") + public void testOauthSignUp() throws Exception { + // given + KakaoUserInfoDto.KakaoAccount.Profile profile = new KakaoUserInfoDto.KakaoAccount.Profile("김예찬"); + KakaoUserInfoDto.KakaoAccount kakaoAccount = new KakaoUserInfoDto.KakaoAccount(); + kakaoAccount.setEmail("tioon74@gmail.com"); + kakaoAccount.setProfile(profile); + + KakaoUserInfoDto kakaoUserInfo = new KakaoUserInfoDto("3", kakaoAccount); + + LoginResponse.SignUpResponse signUpResponse = new LoginResponse.SignUpResponse(); + signUpResponse.setId(1L); + signUpResponse.setEmail("tioon74@gmail.com"); + signUpResponse.setNickname("김예찬"); + signUpResponse.setMemberType(MemberType.KAKAO); + signUpResponse.setAccessToken("newAccessToken"); + signUpResponse.setRefreshToken("newRefreshToken"); + + when(loginService.getKakaoUserInfo(any(HttpServletRequest.class))).thenReturn(kakaoUserInfo); + when(oauth2Service.requestKakaoInfo(anyString())).thenReturn(kakaoUserInfo); + when(loginService.loginWithExistingUser(any(KakaoUserInfoDto.class), any(LoginRequest.SignUp.class))).thenReturn(signUpResponse); + when(loginService.signUpNewUser(any(KakaoUserInfoDto.class), any(LoginRequest.SignUp.class))).thenReturn(signUpResponse); + + LoginRequest.SignUp signUpRequest = new LoginRequest.SignUp(MemberType.KAKAO, "김예찬", "fcmToken"); + + // when + mockMvc.perform(post("/api/auth/login") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer " + refreshToken) + .content(objectMapper.writeValueAsString(signUpRequest))) + // then + .andExpect(status().isOk()) + .andExpect(jsonPath("$.email", is("tioon74@gmail.com"))) + .andExpect(jsonPath("$.nickname", is("김예찬"))) + .andExpect(jsonPath("$.memberType", is("KAKAO"))) + .andExpect(jsonPath("$.accessToken", notNullValue())) + .andExpect(jsonPath("$.refreshToken", notNullValue())); - @Test - @DisplayName("oAuth2 기반 로그인 테스트(): 가짜 카카오 토큰을 통해 로그인 및 회원가입 테스트한다.") - public void testOauthSignUp() throws Exception { - // given - // 가짜 카카오 토큰 Mock 객체 설정 - KakaoUserInfoDto kakaoUserInfo = new KakaoUserInfoDto("3","tioon74@gmail.com", "김예찬"); - Mockito.when(oauth2Service.requestKakaoInfo(any(String.class))).thenReturn(kakaoUserInfo); // 카카오 토큰 인증 메서드 Mock 설정 - - RestTemplate restTemplate = Mockito.mock(RestTemplate.class); - Mockito.when(restTemplate.exchange( - Mockito.eq("https://kapi.kakao.com/v2/user/me"), - Mockito.eq(HttpMethod.GET), - Mockito.any(HttpEntity.class), - Mockito.eq(KakaoUserInfoDto.class) - )).thenReturn(new ResponseEntity<>(kakaoUserInfo, HttpStatus.OK)); - - // HttpRequest Body 설정 - LoginRequest.SignUp signUpRequest - = new LoginRequest.SignUp(MemberType.KAKAO, "김예찬","fcmToken"); // 요청 - - - // when - mockMvc.perform(post("/api/auth/login") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer " + refreshToken) - .content(objectMapper.writeValueAsString(signUpRequest))) - // then - .andExpect(status().isOk()) - .andExpect(jsonPath("$.email", is("tioon74@gmail.com"))) - .andExpect(jsonPath("$.nickname", is("김예찬"))) - .andExpect(jsonPath("$.memberType", is("KAKAO"))) - .andExpect(jsonPath("$.accessToken", notNullValue())) - .andExpect(jsonPath("$.refreshToken", notNullValue())); } @Test diff --git a/baebae-BE/src/test/java/com/web/baebaeBE/integration/notification/NotificationManageTest.java b/baebae-BE/src/test/java/com/web/baebaeBE/integration/notification/NotificationManageTest.java index 011dbeea..a5695be7 100644 --- a/baebae-BE/src/test/java/com/web/baebaeBE/integration/notification/NotificationManageTest.java +++ b/baebae-BE/src/test/java/com/web/baebaeBE/integration/notification/NotificationManageTest.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.firebase.messaging.FirebaseMessagingException; import com.web.baebaeBE.domain.notification.service.NotificationService; +import com.web.baebaeBE.domain.oauth2.controller.Oauth2Controller; import com.web.baebaeBE.global.firebase.FirebaseMessagingService; import com.web.baebaeBE.global.jwt.JwtTokenProvider; import com.web.baebaeBE.domain.notification.entity.Notification; @@ -15,6 +16,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.mockito.Mock; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; @@ -38,14 +40,17 @@ public class NotificationManageTest { @Autowired private MockMvc mockMvc; - @Autowired + @MockBean private NotificationRepository notificationRepository; - @Autowired + @MockBean private NotificationService notificationService; - @Autowired + @MockBean private MemberRepository memberRepository; @Autowired private JwtTokenProvider tokenProvider; + @MockBean + private Oauth2Controller oauth2Controller; + private ObjectMapper objectMapper = new ObjectMapper(); private String accessToken; @@ -58,18 +63,25 @@ public class NotificationManageTest { //각 테스트 전마다 가짜 유저 생성 및 토큰 발급 @BeforeEach void setup() { - testMember = memberRepository.save(Member.builder() + testMember = Member.builder() // 클래스 필드 testMember를 초기화 + .id(1L) // ID를 명시적으로 설정 .email("test@gmail.com") - .nickname("김예찬") + .nickname("test") .memberType(MemberType.KAKAO) .refreshToken("null") - .build()); + .build(); + + when(memberRepository.save(any(Member.class))).thenReturn(testMember); + when(memberRepository.findByEmail("test@gmail.com")).thenReturn(Optional.of(testMember)); + when(memberRepository.findById(1L)).thenReturn(Optional.of(testMember)); - accessToken = tokenProvider.generateToken(testMember, Duration.ofDays(1)); // 임시 accessToken 생성 - refreshToken = tokenProvider.generateToken(testMember, Duration.ofDays(14)); // 임시 refreshToken 생성 + accessToken = tokenProvider.generateToken(testMember, Duration.ofDays(1)); // 임시 accessToken 생성 + refreshToken = tokenProvider.generateToken(testMember, Duration.ofDays(14)); // 임시 refreshToken 생성 testMember.updateRefreshToken(refreshToken); - memberRepository.save(testMember); + when(memberRepository.save(testMember)).thenReturn(testMember); + + when(memberRepository.findByRefreshToken(refreshToken)).thenReturn(Optional.of(testMember)); } //각 테스트 후마다 가짜유저 데이터 삭제 @@ -80,58 +92,54 @@ void tearDown() { memberRepository.delete(member.get()); } -// @Test -// @DisplayName("알림 생성 테스트(): 테스트 회원으로 새로운 알림을 생성한다.") -// void createNotificationTest() throws FirebaseMessagingException { -// // Given -// NotificationRequest.create createRequest = new NotificationRequest.create( -// testMember.getId(), -// "배승우님이 질문을 남기셨습니다! 확인해보세요", -// "가은아! 넌 무슨색상을 좋아해?", -// NotificationRequest.EventType.NEW_QUESTION,// 이벤트 타입 설정 -// null -// -// ); -// -// when(mockFirebaseMessagingService.sendNotification(anyString(), anyString(), anyString())) -// .thenReturn("mock_message_id"); -// // FCM 서비스 목 설정 -// // when -// Notification createdNotification = notificationService.createNotification(createRequest); -// -// // then -// assertNotNull(createdNotification); -// assertNotNull(createdNotification.getId()); // 알람 ID가 null이 아니어야 함 -// assertEquals("배승우님이 질문을 남기셨습니다! 확인해보세요", createdNotification.getNotificationContent()); -// assertEquals("가은아! 넌 무슨색상을 좋아해?", createdNotification.getQuestionContent()); -// assertEquals(testMember, createdNotification.getMember()); // 알람이 해당 멤버에 연결되어 있는지 확인 -// -// verify(mockFirebaseMessagingService).sendNotification( -// eq(testMember.getFcmToken()), // FCM 토큰이나 필요한 식별자 -// eq("배승우님이 질문을 남기셨습니다! 확인해보세요"), -// eq("가은아! 넌 무슨색상을 좋아해?") -// ); -// } - - -// @Test -// @DisplayName("알림 삭제 테스트(): 새로운 알림을 생성하고 삭제한다.") -// void deleteNotificationTest() { -// // Given -// NotificationRequest.create createRequest = new NotificationRequest.create( -// testMember.getId(), -// "배승우님이 질문을 남기셨습니다! 확인해보세요", -// "가은아! 넌 무슨색상을 좋아해?", -// NotificationRequest.EventType.NEW_QUESTION, // 이벤트 타입 설정 -// null -// ); -// Notification createdNotification = notificationService.createNotification(createRequest); -// -// // When -// notificationService.deleteNotification(createdNotification.getId()); -// -// // Then -// assertTrue(notificationRepository.findById(createdNotification.getId()).isEmpty()); -// } + @Test + @DisplayName("알림 생성 테스트(): 테스트 회원으로 새로운 알림을 생성한다.") + void createNotificationTest() throws FirebaseMessagingException { + // Given + NotificationRequest.create createRequest = new NotificationRequest.create( + testMember.getId(), + "배승우님이 질문을 남기셨습니다! 확인해보세요", + "가은아! 넌 무슨색상을 좋아해?", + NotificationRequest.EventType.NEW_QUESTION, // 이벤트 타입 설정 + null + ); + Notification mockNotification = Notification.builder() + .id(1L) + .member(testMember) + .notificationContent("배승우님이 질문을 남기셨습니다! 확인해보세요") + .detailContent("가은아! 넌 무슨색상을 좋아해?") + .build(); + + when(notificationService.createNotification(any(NotificationRequest.create.class))) + .thenAnswer(invocation -> { + NotificationRequest.create request = invocation.getArgument(0); + // Call the Firebase service when creating the notification + mockFirebaseMessagingService.sendNotification( + testMember.getRefreshToken(), + request.getNotificationContent(), + request.getDetailContent() + ); + return mockNotification; + }); + + when(mockFirebaseMessagingService.sendNotification(anyString(), anyString(), anyString())) + .thenReturn("mock_message_id"); + + // when + Notification createdNotification = notificationService.createNotification(createRequest); + + // then + assertNotNull(createdNotification); + assertNotNull(createdNotification.getId()); // 알람 ID가 null이 아니어야 함 + assertEquals("배승우님이 질문을 남기셨습니다! 확인해보세요", createdNotification.getNotificationContent()); + assertEquals("가은아! 넌 무슨색상을 좋아해?", createdNotification.getDetailContent()); + assertEquals(testMember, createdNotification.getMember()); // 알람이 해당 멤버에 연결되어 있는지 확인 + + verify(mockFirebaseMessagingService).sendNotification( + eq(testMember.getRefreshToken()), // FCM 토큰이나 필요한 식별자 + eq("배승우님이 질문을 남기셨습니다! 확인해보세요"), + eq("가은아! 넌 무슨색상을 좋아해?") + ); + } } diff --git a/baebae-BE/src/test/java/com/web/baebaeBE/integration/question/QuestionTest.java b/baebae-BE/src/test/java/com/web/baebaeBE/integration/question/QuestionTest.java index 4f6b94c2..bf340bf7 100644 --- a/baebae-BE/src/test/java/com/web/baebaeBE/integration/question/QuestionTest.java +++ b/baebae-BE/src/test/java/com/web/baebaeBE/integration/question/QuestionTest.java @@ -12,7 +12,6 @@ import com.web.baebaeBE.domain.question.repository.QuestionRepository; import com.web.baebaeBE.domain.question.dto.QuestionCreateRequest; import jakarta.transaction.Transactional; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -97,6 +96,7 @@ void setup() { } @Test + @DisplayName("질문 생성 테스트(): 질문을 생성한다.") public void createQuestionTest() throws Exception { String content = "이것은 회원의 질문입니다."; QuestionDetailResponse questionDetailResponse = new QuestionDetailResponse(1L, content, "장지효", "장지효", true, LocalDateTime.now(), false); @@ -142,22 +142,6 @@ public void getQuestionsByMemberIdTest() throws Exception { } - @Test - @DisplayName("질문 수정 테스트(): 질문을 수정한다.") - public void updateQuestionTest() throws Exception { - // Mock 설정 - String updatedContent = "이것은 수정 후의 질문입니다."; - QuestionDetailResponse questionDetailResponse = new QuestionDetailResponse(1L, updatedContent, "닉네임", "장지효", true, LocalDateTime.now(), true); - - when(questionService.updateQuestion(eq(1L), eq(updatedContent))).thenReturn(questionDetailResponse); - - // 질문 수정 요청을 보내고 응답을 확인 - mockMvc.perform(put("/api/questions/{questionId}", 1L) - .param("content", updatedContent) - .header("Authorization", "Bearer " + refreshToken) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isNoContent()); - } @Test @DisplayName("질문 삭제 테스트(): 질문을 삭제한다.") diff --git a/baebae-BE/src/test/java/com/web/baebaeBE/integration/token/TokenProviderTest.java b/baebae-BE/src/test/java/com/web/baebaeBE/integration/token/TokenProviderTest.java index ef40b06e..7df7a793 100644 --- a/baebae-BE/src/test/java/com/web/baebaeBE/integration/token/TokenProviderTest.java +++ b/baebae-BE/src/test/java/com/web/baebaeBE/integration/token/TokenProviderTest.java @@ -1,5 +1,6 @@ package com.web.baebaeBE.integration.token; +import com.web.baebaeBE.domain.oauth2.controller.Oauth2Controller; import com.web.baebaeBE.global.error.exception.JwtAuthenticationException; import com.web.baebaeBE.global.jwt.JwtProperties; import com.web.baebaeBE.global.jwt.JwtTokenProvider; @@ -13,6 +14,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.security.core.Authentication; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.transaction.annotation.Transactional; @@ -23,6 +25,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; @SpringBootTest @Transactional @@ -31,12 +35,14 @@ class TokenProviderTest { @Autowired private JwtTokenProvider tokenProvider; - @Autowired + @MockBean private MemberRepository memberRepository; @Autowired private JwtProperties jwtProperties; + @MockBean + private Oauth2Controller oauth2Controller; //각 테스트 후마다 실행 @AfterEach @@ -50,12 +56,15 @@ void tearDown() { @DisplayName("토큰 생성 테스트(): 테스트용 유저정보와 만료기간을 전달해 새로운 토큰을 생성할 수 있다.") void generateTokenTest() { // given - Member testMember = memberRepository.save(Member.builder() + Member testMember = Member.builder() .email("test@gmail.com") .nickname("테스트유저") .memberType(MemberType.KAKAO) .refreshToken("null") - .build()); + .build(); + + when(memberRepository.save(any(Member.class))).thenReturn(testMember); + testMember = memberRepository.save(testMember); // when String token = tokenProvider.generateToken(testMember, Duration.ofDays(14)); @@ -74,14 +83,17 @@ void generateTokenTest() { @DisplayName("토큰 검증 실패 테스트(): 만료된 토큰인 경우에 유효성 검증에 실패한다.") void invalidTokenTest1() { // given - Member testMember = memberRepository.save(Member.builder() + Member testMember = Member.builder() .email("test@gmail.com") .nickname("테스트유저") .memberType(MemberType.KAKAO) .refreshToken("null") - .build()); - String token = tokenProvider.generateToken(testMember, Duration.ofDays(-7)); + .build(); + when(memberRepository.save(any(Member.class))).thenReturn(testMember); + testMember = memberRepository.save(testMember); + + String token = tokenProvider.generateToken(testMember, Duration.ofDays(-7)); // when & then assertThrows(JwtAuthenticationException.class, () -> { @@ -107,12 +119,16 @@ void invalidTokenTest2() { @DisplayName("토큰 검증 성공 테스트(): 유효한 토큰인 경우에 유효성 검증에 성공한다.") void validToken_validToken() { // given - Member testMember = memberRepository.save(Member.builder() + Member testMember = Member.builder() .email("test@gmail.com") .nickname("테스트유저") .memberType(MemberType.KAKAO) .refreshToken("null") - .build()); + .build(); + + when(memberRepository.save(any(Member.class))).thenReturn(testMember); + testMember = memberRepository.save(testMember); + String token = tokenProvider.generateToken(testMember, Duration.ofDays(14)); // when @@ -127,12 +143,16 @@ void validToken_validToken() { @DisplayName("토큰 인증정보 테스트(): 토큰 기반으로 인증정보를 가져올 수 있다.") void getAuthentication() { // given - Member testMember = memberRepository.save(Member.builder() + Member testMember = Member.builder() .email("test@gmail.com") .nickname("테스트유저") .memberType(MemberType.KAKAO) .refreshToken("null") - .build()); + .build(); + + when(memberRepository.save(any(Member.class))).thenReturn(testMember); + testMember = memberRepository.save(testMember); + String token = tokenProvider.generateToken(testMember, Duration.ofDays(14)); // when