diff --git a/src/main/java/org/tenten/tentenbe/domain/comment/model/Comment.java b/src/main/java/org/tenten/tentenbe/domain/comment/model/Comment.java index 277836fd..e5e07cb9 100644 --- a/src/main/java/org/tenten/tentenbe/domain/comment/model/Comment.java +++ b/src/main/java/org/tenten/tentenbe/domain/comment/model/Comment.java @@ -34,42 +34,41 @@ public class Comment extends BaseTimeEntity { private Review review; - public Comment(String content , Review review ){ + public Comment(String content , Review review, Member member ){ this.content = content; this.review = review; - // this.creator = creator; + this.creator = member; } public void UpdateComment(String content){ this.content = content; } - // 리뷰와 댓글 양방향 설정 만약 리뷰에서 설정되어있으면 제거해도됨 - public void addReview(Review review){ - this.review = review; - - if(!review.getComments().contains(this)){ - review.getComments().add(this); - } - } - public void removeReview(){ - if(this.review != null){ - review.getComments().remove(this); - this.review = null; - } - } - - public void addCreator(Member creator){ - this.creator = creator; - - if(!creator.getComments().contains(this)){ - creator.getComments().add(this); - } - } - public void removeCreator(){ - if(this.creator != null){ - creator.getComments().remove(this); - this.creator = null; - } - } +// public void addReview(Review review){ +// this.review = review; +// +// if(!review.getComments().contains(this)){ +// review.getComments().add(this); +// } +// } +// public void removeReview(){ +// if(this.review != null){ +// review.getComments().remove(this); +// this.review = null; +// } +// } +// +// public void addCreator(Member creator){ +// this.creator = creator; +// +// if(!creator.getComments().contains(this)){ +// creator.getComments().add(this); +// } +// } +// public void removeCreator(){ +// if(this.creator != null){ +// creator.getComments().remove(this); +// this.creator = null; +// } +// } } diff --git a/src/main/java/org/tenten/tentenbe/domain/comment/service/CommentService.java b/src/main/java/org/tenten/tentenbe/domain/comment/service/CommentService.java index ad2bc038..7434b2c2 100644 --- a/src/main/java/org/tenten/tentenbe/domain/comment/service/CommentService.java +++ b/src/main/java/org/tenten/tentenbe/domain/comment/service/CommentService.java @@ -13,6 +13,7 @@ import org.tenten.tentenbe.domain.member.exception.MemberException; import org.tenten.tentenbe.domain.member.model.Member; import org.tenten.tentenbe.domain.member.repository.MemberRepository; +import org.tenten.tentenbe.domain.review.exception.ReviewException; import org.tenten.tentenbe.domain.review.model.Review; import org.tenten.tentenbe.domain.review.repository.ReviewRepository; @@ -28,15 +29,11 @@ public class CommentService { @Transactional public CommentInfo createComment(Long currentMemberId, CommentCreateRequest commentCreateRequest) { - Review review = reviewRepository.findById(commentCreateRequest.reviewId()).orElseThrow( - ()-> new RuntimeException("해당 리뷰가 없습니다.") - ); - - Comment newComment = new Comment(commentCreateRequest.content(), review); + Review review = reviewRepository.findById(commentCreateRequest.reviewId()) + .orElseThrow(() -> new ReviewException("해당 아이디로 존재하는 리뷰가 없습니다. reviewId : " + commentCreateRequest.reviewId(), NOT_FOUND)); Member member = memberRepository.findById(currentMemberId).orElseThrow(() -> new MemberException("주어진 아이디로 존재하는 멤버가 없습니다.", NOT_FOUND)); - newComment.addReview(review); - newComment.addCreator(member); + Comment newComment = new Comment(commentCreateRequest.content(), review,member); Comment savedComment = commentRepository.save(newComment); return new CommentInfo( @@ -45,7 +42,7 @@ public CommentInfo createComment(Long currentMemberId, CommentCreateRequest comm member.getProfileImageUrl(), savedComment.getContent(), savedComment.getCreatedTime(), - true + true ); } @@ -54,9 +51,11 @@ public CommentInfo updateComment(Long memberId, Long commentId, CommentUpdateReq Member member = memberRepository.findById(memberId).orElseThrow(() -> new MemberException("주어진 아이디로 존재하는 멤버가 없습니다.", NOT_FOUND)); Comment findCommentById = commentRepository.findById(commentId).orElseThrow( - () -> new CommentException("해당 댓글이 없습니다.", HttpStatus.BAD_REQUEST) + () -> new CommentException("해당 댓글이 없습니다.", NOT_FOUND) ); + commentEditPermission(member,findCommentById); + findCommentById.UpdateComment(commentUpdateRequest.content()); return new CommentInfo( findCommentById.getId(), @@ -71,13 +70,18 @@ public CommentInfo updateComment(Long memberId, Long commentId, CommentUpdateReq @Transactional public void deleteComment(Long memberId, Long commentId) { + Member member = memberRepository.findById(memberId).orElseThrow(() -> new MemberException("주어진 아이디로 존재하는 멤버가 없습니다.", NOT_FOUND)); Comment findCommentById = commentRepository.findById(commentId).orElseThrow( - () -> new CommentException("해당 댓글이 없습니다.", HttpStatus.BAD_REQUEST) + () -> new CommentException("해당 댓글이 없습니다.", NOT_FOUND) ); - findCommentById.removeReview(); - findCommentById.removeCreator(); - + commentEditPermission(member,findCommentById); commentRepository.delete(findCommentById); } + + private void commentEditPermission(Member member, Comment comment){ + if(member.getId() != comment.getCreator().getId()){ + throw new CommentException("댓글 수정 권한이 없습니다.",HttpStatus.FORBIDDEN); + } + } } diff --git a/src/test/java/org/tenten/tentenbe/common/ControllerTest.java b/src/test/java/org/tenten/tentenbe/common/ControllerTest.java new file mode 100644 index 00000000..5b5adc25 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/common/ControllerTest.java @@ -0,0 +1,36 @@ +package org.tenten.tentenbe.common; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +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.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; +import org.tenten.tentenbe.domain.member.service.MemberService; + +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +public class ControllerTest { + + @Autowired + protected MockMvc mockMvc; + @Autowired + protected ObjectMapper objectMapper; + @Autowired + WebApplicationContext context; + @BeforeEach + protected void setup() { + System.out.println("start before Each"); + mockMvc = MockMvcBuilders + .webAppContextSetup(this.context) + .apply(springSecurity()) + .build(); + } +} diff --git a/src/test/java/org/tenten/tentenbe/common/RepositoryTest.java b/src/test/java/org/tenten/tentenbe/common/RepositoryTest.java new file mode 100644 index 00000000..bde23bac --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/common/RepositoryTest.java @@ -0,0 +1,64 @@ +package org.tenten.tentenbe.common; + + +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.junit.jupiter.api.BeforeEach; +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.test.context.ActiveProfiles; +import org.tenten.tentenbe.domain.liked.repository.LikedItemRepository; +import org.tenten.tentenbe.domain.member.repository.MemberRepository; +import org.tenten.tentenbe.domain.review.repository.KeywordRepository; +import org.tenten.tentenbe.domain.review.repository.ReviewKeywordRepository; +import org.tenten.tentenbe.domain.review.repository.ReviewRepository; +import org.tenten.tentenbe.domain.tour.repository.TourItemRepository; +import org.tenten.tentenbe.domain.trip.repository.*; + +@DataJpaTest +@ActiveProfiles("test") +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +public class RepositoryTest { + + @Autowired + protected TourItemRepository tourItemRepository; + @Autowired + protected MemberRepository memberRepository; + @Autowired + protected LikedItemRepository likedItemRepository; + @Autowired + protected ReviewRepository reviewRepository; + @Autowired + protected TripRepository tripRepository; + @Autowired + protected TripItemRepository tripItemRepository; + @Autowired + protected TripMemberRepository tripMemberRepository; + @Autowired + protected TripLikedItemRepository tripLikedItemRepository; + @Autowired + protected TripLikedItemPreferenceRepository tripLikedItemPreferenceRepository; + @Autowired + protected ReviewKeywordRepository reviewKeywordRepository; + @Autowired + protected KeywordRepository keywordRepository; + @PersistenceContext + protected EntityManager entityManager; + @BeforeEach + protected void init() { + entityManager.flush(); + System.out.println("flushed data success"); + tourItemRepository.deleteAll(); + memberRepository.deleteAll(); + likedItemRepository.deleteAll(); + tripRepository.deleteAll(); + tripItemRepository.deleteAll(); + reviewRepository.deleteAll(); + tripMemberRepository.deleteAll(); + tripLikedItemRepository.deleteAll(); + tripLikedItemPreferenceRepository.deleteAll(); + System.out.println("reset success"); + } + +} diff --git a/src/test/java/org/tenten/tentenbe/common/ServiceTest.java b/src/test/java/org/tenten/tentenbe/common/ServiceTest.java new file mode 100644 index 00000000..a978ea14 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/common/ServiceTest.java @@ -0,0 +1,10 @@ +package org.tenten.tentenbe.common; + +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.context.ActiveProfiles; + +@ExtendWith(MockitoExtension.class) +@ActiveProfiles("test") +public class ServiceTest { +} diff --git a/src/test/java/org/tenten/tentenbe/common/fixture/AuthFixture.java b/src/test/java/org/tenten/tentenbe/common/fixture/AuthFixture.java new file mode 100644 index 00000000..8b45c8ad --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/common/fixture/AuthFixture.java @@ -0,0 +1,109 @@ +package org.tenten.tentenbe.common.fixture; + +import org.tenten.tentenbe.domain.auth.dto.request.LoginRequest; +import org.tenten.tentenbe.domain.auth.dto.request.SignUpRequest; +import org.tenten.tentenbe.domain.auth.dto.response.LoginResponse; +import org.tenten.tentenbe.domain.auth.dto.response.MemberDto; +import org.tenten.tentenbe.domain.auth.dto.response.SignUpResponse; +import org.tenten.tentenbe.domain.member.dto.request.MemberUpdateRequest; +import org.tenten.tentenbe.domain.member.model.Member; +import org.tenten.tentenbe.domain.member.model.Survey; +import org.tenten.tentenbe.domain.token.dto.TokenDTO; +import org.tenten.tentenbe.global.common.enums.GenderType; +import org.tenten.tentenbe.global.common.enums.LoginType; +import org.tenten.tentenbe.global.security.jwt.model.RefreshToken; + +import java.sql.Timestamp; +import java.time.Instant; + +import static org.tenten.tentenbe.domain.token.dto.TokenDTO.*; +import static org.tenten.tentenbe.global.common.constant.JwtConstants.ACCESS_TOKEN_EXPIRE_TIME; +import static org.tenten.tentenbe.global.common.constant.JwtConstants.BEARER_TYPE; +import static org.tenten.tentenbe.global.common.enums.AgeType.TEENAGER; +import static org.tenten.tentenbe.global.common.enums.GenderType.DEFAULT; +import static org.tenten.tentenbe.global.common.enums.LoginType.EMAIL; +import static org.tenten.tentenbe.global.common.enums.UserAuthority.ROLE_USER; + +public class AuthFixture { + + public static SignUpRequest signUpRequest(){ + return new SignUpRequest("test@gmail.com", "qwerty1234"); + } + + public static SignUpResponse signUpResponse(){ + return new SignUpResponse(1L, "test@gmail.com", "test", null); + } + + + public static LoginRequest loginRequest(){ + return new LoginRequest("test@gmail.com", "qwerty1234"); + } + + public static LoginResponse loginResponse(){ + return LoginResponse.builder() + .memberDto( + MemberDto.builder() + .id(1L) + .nickName("test") + .email("test@gmail.com") + .build() + ) + .tokenInfo(TokenDTO.TokenIssueDTO.builder() + .accessToken("c2lsdmVfijhtroiehJ432NwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQtc2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQK") + .accessTokenExpiresIn(ACCESS_TOKEN_EXPIRE_TIME) + .grantType(BEARER_TYPE) + .build()) + .build(); + } + + public static Member newBasicMember(){ + return Member.builder() + .id(1L) + .ageType(TEENAGER) + .loginType(LoginType.EMAIL) + .nickname("nickNameTest") + .password("$10$ygrAExVYmFTkZn2d0.Pk3Ot5CNZwIBjZH5f.WW0AnUq4w4PtBi9Nm") + .profileImageUrl("naver.com") + .userAuthority(ROLE_USER) + .email("test@gmail.com") + .survey(new Survey("계획성", "활동성", "숙소", "음식", "여행 스타일")) + .build(); + } + + public static Member updateMember(){ + return Member.builder() + .id(2L) + .ageType(TEENAGER) + .loginType(LoginType.EMAIL) + .genderType(GenderType.DEFAULT) + .nickname("update my nickName") + .password("$10$ygrAExVYmFTkZn2d0.Pk3Ot5CNZwIBjZH5f.WW0AnUq4w4PtBi9Nm") + .profileImageUrl("updateNaver.com") + .userAuthority(ROLE_USER) + .email("test@gmail.com") + .build(); + } + public static Member newMember(){ + return signUpRequest().toEntity("$10$ygrAExVYmFTkZn2d0.Pk3Ot5CNZwIBjZH5f.WW0AnUq4w4PtBi9Nm", EMAIL, ROLE_USER); + } + + public static RefreshToken refreshToken(){ + return RefreshToken.builder() + .member(Member.builder() + .id(1L) + .ageType(TEENAGER) + .loginType(LoginType.EMAIL) + .nickname("test") + .password("$10$ygrAExVYmFTkZn2d0.Pk3Ot5CNZwIBjZH5f.WW0AnUq4w4PtBi9Nm") + .profileImageUrl("naver.com") + .userAuthority(ROLE_USER) + .email("test@gmail.com") + .build()) + .token("c2lsdmVfijhtroiehJ432NwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQtc2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQK") + .build(); + } + + public static MemberUpdateRequest memberUpdateRequest(){ + return new MemberUpdateRequest("update my nickName","updateNaver.com",TEENAGER,DEFAULT); + } +} diff --git a/src/test/java/org/tenten/tentenbe/common/fixture/CommentFixture.java b/src/test/java/org/tenten/tentenbe/common/fixture/CommentFixture.java new file mode 100644 index 00000000..95580b5c --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/common/fixture/CommentFixture.java @@ -0,0 +1,56 @@ +package org.tenten.tentenbe.common.fixture; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.tenten.tentenbe.domain.comment.dto.request.CommentCreateRequest; +import org.tenten.tentenbe.domain.comment.dto.request.CommentUpdateRequest; +import org.tenten.tentenbe.domain.comment.dto.response.CommentInfo; +import org.tenten.tentenbe.domain.comment.dto.response.CommentResponse; +import org.tenten.tentenbe.domain.comment.model.Comment; +import org.tenten.tentenbe.domain.member.model.Member; +import org.tenten.tentenbe.domain.review.dto.response.KeywordResponse; +import org.tenten.tentenbe.domain.review.model.Review; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Date; +import java.util.List; + +import static org.tenten.tentenbe.common.fixture.AuthFixture.newBasicMember; +import static org.tenten.tentenbe.common.fixture.AuthFixture.updateMember; +import static org.tenten.tentenbe.common.fixture.ReviewFixture.review; + +public class CommentFixture { + + + public static CommentInfo commentInfo(){ + return new CommentInfo(1L, "comment Nick name", "profile image url", + "comment test content", LocalDateTime.now(), true); + } + + public static CommentResponse commentResponse(){ + Pageable pageable = PageRequest.of(0, 10); + List commentInfos = List.of(commentInfo()); + Page commentInfoPage = new PageImpl<>(commentInfos, pageable, commentInfos.size()); + return new CommentResponse(commentInfoPage); + } + + public static CommentCreateRequest commentCreateRequest (){ + return new CommentCreateRequest("success create comment", 1L); + } + + public static CommentUpdateRequest commentUpdateRequest(){ + return new CommentUpdateRequest("update comment"); + } + + public static Comment comment(){ + return new Comment("comment content", review(), updateMember()); + } + + public static Comment saveComment(String content, Review review, Member member){ + return new Comment(content, review, member); + } + +} diff --git a/src/test/java/org/tenten/tentenbe/common/fixture/MemberFixture.java b/src/test/java/org/tenten/tentenbe/common/fixture/MemberFixture.java new file mode 100644 index 00000000..dfc5d5a8 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/common/fixture/MemberFixture.java @@ -0,0 +1,92 @@ +package org.tenten.tentenbe.common.fixture; + +import org.tenten.tentenbe.domain.liked.model.LikedItem; +import org.tenten.tentenbe.domain.member.model.Member; +import org.tenten.tentenbe.domain.member.model.Survey; +import org.tenten.tentenbe.domain.review.model.Review; +import org.tenten.tentenbe.domain.tour.model.TourItem; + +import static org.tenten.tentenbe.common.fixture.AuthFixture.*; + +public class MemberFixture { + + public static TourItem tourItem(){ + return TourItem.builder() + .id(1L) + .contentId(1L) + .contentTypeId(1L) + .areaCode(1L) + .subAreaCode(1L) + .address("test address") + .detailedAddress("test detail address") + .originalThumbnailUrl("origin thumnail url") + .smallThumbnailUrl("small thumnail url") + .title("test title") + .zipcode("test zip code") + .tel("test telephone") + .longitude("longitude") + .latitude("latitude") + .reviewTotalCount(10L) + .likedTotalCount(20L) + .build(); + } + + public static TourItem tourItemSecond(){ + return TourItem.builder() + .id(1L) + .contentId(1L) + .contentTypeId(12L) + .areaCode(1L) + .subAreaCode(1L) + .address("search address") + .detailedAddress("search address") + .originalThumbnailUrl("origin thumnail url") + .smallThumbnailUrl("small thumnail url") + .title("test title") + .zipcode("test zip code") + .tel("test telephone") + .longitude("longitude") + .latitude("latitude") + .reviewTotalCount(10L) + .likedTotalCount(20L) + .build(); + } + + + public static LikedItem likedItem(){ + return LikedItem.builder() + .id(1L) + .member(newMember()) + .tourItem(tourItem()) + .build(); + } + + public static LikedItem likedSaveItem(Member member, TourItem tourItem){ + return LikedItem.builder() + .member(member) + .tourItem(tourItem) + .build(); + } + + + public static LikedItem serviceLikedItem(){ + return LikedItem.builder() + .id(1L) + .member(newBasicMember()) + .tourItem(tourItem()) + .build(); + } + + + public static Survey survey(){ + return new Survey("계획성", "활동성", "숙소", "음식", "여행 스타일"); + } + + public static Survey updateSurvey(){ + return new Survey("철저하게", "아침형", "분위기", "음식", "액티비티"); + } + + + + +} diff --git a/src/test/java/org/tenten/tentenbe/common/fixture/ReviewFixture.java b/src/test/java/org/tenten/tentenbe/common/fixture/ReviewFixture.java new file mode 100644 index 00000000..fd47334f --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/common/fixture/ReviewFixture.java @@ -0,0 +1,117 @@ +package org.tenten.tentenbe.common.fixture; + +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.tenten.tentenbe.domain.member.model.Member; +import org.tenten.tentenbe.domain.review.dto.request.ReviewCreateRequest; +import org.tenten.tentenbe.domain.review.dto.request.ReviewKeywordCreateRequest; +import org.tenten.tentenbe.domain.review.dto.request.ReviewUpdateRequest; +import org.tenten.tentenbe.domain.review.dto.response.*; +import org.tenten.tentenbe.domain.review.model.Keyword; +import org.tenten.tentenbe.domain.review.model.Review; +import org.tenten.tentenbe.domain.review.model.ReviewKeyword; +import org.tenten.tentenbe.domain.tour.model.TourItem; + +import java.util.List; + +import static org.tenten.tentenbe.common.fixture.AuthFixture.newBasicMember; +import static org.tenten.tentenbe.common.fixture.MemberFixture.tourItem; +import static org.tenten.tentenbe.global.common.enums.KeywordType.DINING_KEYWORD; + +public class ReviewFixture { + + public static Review review() { + return Review.builder() + .id(1L) + .rating(20.5) + .content("hello world") + .tourItem(tourItem()) + .creator(newBasicMember()) + .build(); + } + + public static Review updateReview() { + return Review.builder() + .id(1L) + .rating(20.5) + .content("update Review") + .tourItem(tourItem()) + .creator(newBasicMember()) + .build(); + } + + public static Review saveReview(TourItem tourItem, Member member) { + return Review.builder() + .id(1L) + .rating(20.5) + .content("saved review") + .tourItem(tourItem) + .creator(member) + .build(); + } + + public static ReviewInfo saveReviewInfo(Review review, Member member) { + return ReviewInfo.fromEntity(review, member.getId()); + } + + public static ReviewInfo reviewInfo() { + return ReviewInfo.fromEntity(review(), newBasicMember().getId()); + } + + + public static ReviewKeywordCreateRequest reviewKeywordCreateRequest() { + return new ReviewKeywordCreateRequest(1L, "review Key Word"); + } + + public static ReviewCreateRequest reviewCreateRequest() { + return new ReviewCreateRequest(1L, 2.5D, List.of(reviewKeywordCreateRequest()), "review content test"); + } + + public static ReviewUpdateRequest reviewUpdateRequest() { + return new ReviewUpdateRequest(42.3, List.of(reviewKeywordCreateRequest()), "Review Update Content"); + } + + + public static ReviewResponse reviewResponse() { + Pageable pageable = PageRequest.of(0, 10); + List reviewInfos = List.of(ReviewInfo.fromEntity(review(), AuthFixture.newBasicMember().getId())); + return + new ReviewResponse( + 20.2, + tourItem().getReviewTotalCount(), + 15L, + new PageImpl<>(reviewInfos, pageable, reviewInfos.size()), + List.of(new TourKeywordInfo(1L, "깨끗해요", DINING_KEYWORD, 2L)) + ); + + } + + public static Keyword keyword() { + return new Keyword(1L, "save keyword content", DINING_KEYWORD); + } + + public static KeywordInfo keywordInfo() { + return KeywordInfo.fromEntity(keyword()); + } + + public static KeywordResponse keywordResponse() { + return new KeywordResponse(List.of(keywordInfo())); + } + + public static TourKeywordInfo tourKeywordInfo() { + return new TourKeywordInfo(1L, "tour keyword info test", DINING_KEYWORD, 10L); + } + + public static ReviewKeyword reviewKeyword() { + return new ReviewKeyword(1L, review(), keyword()); + } + + public static ReviewKeyword saveReviewKeyword(Review review,Keyword keyword) { + return ReviewKeyword.builder() + .keyword(keyword) + .review(review) + .build(); + } + +} diff --git a/src/test/java/org/tenten/tentenbe/common/fixture/TourFixture.java b/src/test/java/org/tenten/tentenbe/common/fixture/TourFixture.java new file mode 100644 index 00000000..445e500b --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/common/fixture/TourFixture.java @@ -0,0 +1,17 @@ +package org.tenten.tentenbe.common.fixture; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.tenten.tentenbe.domain.tour.dto.response.TourSimpleResponse; + +import java.util.List; + +public class TourFixture { + public static Page tourSimpleResponsePage() { + List tourSimpleResponse = List.of(TourSimpleResponse.fromEntity(MemberFixture.tourItem())); + Pageable pageable = PageRequest.of(0, 10); + return new PageImpl<>(tourSimpleResponse, pageable, tourSimpleResponse.size()); + } +} diff --git a/src/test/java/org/tenten/tentenbe/common/fixture/TripFixture.java b/src/test/java/org/tenten/tentenbe/common/fixture/TripFixture.java new file mode 100644 index 00000000..63101b74 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/common/fixture/TripFixture.java @@ -0,0 +1,168 @@ +package org.tenten.tentenbe.common.fixture; + +import org.tenten.tentenbe.domain.member.model.Member; +import org.tenten.tentenbe.domain.tour.model.TourItem; +import org.tenten.tentenbe.domain.trip.dto.request.TripCreateRequest; +import org.tenten.tentenbe.domain.trip.dto.request.TripInfoUpdateRequest; +import org.tenten.tentenbe.domain.trip.dto.request.TripLikedItemRequest; +import org.tenten.tentenbe.domain.trip.dto.response.*; +import org.tenten.tentenbe.domain.trip.model.*; +import org.tenten.tentenbe.global.common.enums.TripAuthority; + +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; + +import static org.tenten.tentenbe.common.fixture.AuthFixture.newBasicMember; +import static org.tenten.tentenbe.common.fixture.MemberFixture.tourItem; +import static org.tenten.tentenbe.global.common.enums.Transportation.PUBLIC_TRANSPORTATION; +import static org.tenten.tentenbe.global.common.enums.TripAuthority.READ_ONLY; + +public class TripFixture { + + public static Trip trip(){ + return Trip.builder() + .id(10L) + .tripName("test trip name") + .numberOfPeople(4L) + .startDate(LocalDate.parse("2024-01-01")) + .endDate(LocalDate.parse("2024-01-06")) + .isDeleted(false) + .area(null) + .subarea(null) + .budget(10L) + .build(); + } + + public static TripItem savetripItem(Trip trip,TourItem tourItem){ + return TripItem.builder() + .transportation(PUBLIC_TRANSPORTATION) + .seqNum(1L) + .visitDate(LocalDate.parse("2024-01-01")) + .price(200000L) + .trip(trip) + .tourItem(tourItem) + .build(); + + } + public static TripCreateRequest tripCreateRequest(){ + return new TripCreateRequest( + Optional.of("my first trip"), + Optional.of(4L), + Optional.of(LocalDate.parse("2024-01-01")), + Optional.of(LocalDate.parse("2024-01-06")), + Optional.of("강원도"), + Optional.of("강릉시") + ); + } + + public static TripSimpleResponse tripSimpleResponse(){ + return new TripSimpleResponse( + 1L, + "my first trip response", + LocalDate.parse("2024-01-01"), + LocalDate.parse("2024-01-06"), + 4L, + "traveling", + "tripThumbnail.com" + ); + } + + public static TripDetailResponse tripDetailResponse(){ + return new TripDetailResponse( + "trip name test", + LocalDate.parse("2024-01-01"), + LocalDate.parse("2024-01-06") + ); + } + + public static TripInfoUpdateResponse tripInfoUpdateResponse(){ + return new TripInfoUpdateResponse( + "my second trip response", + 4L, + LocalDate.parse("2024-01-01"), + LocalDate.parse("2024-01-06"), + "서울시", + "강남구" + ); + + } + + public static TripInfoUpdateRequest tripInfoUpdateRequest(){ + return new TripInfoUpdateRequest( + "my second trip request", + 4L, + LocalDate.parse("2024-01-01"), + LocalDate.parse("2024-01-06"), + "서울시", + "강남구" + ); + + } + + public static TripLikedSimpleResponse tripLikedSimpleResponse(){ + return new TripLikedSimpleResponse( + 1L, + 1L, + 1L, + 2.5d, + 10L, + true, + false, + 4L, + 3L + + ); + } + + public static TripLikedItemRequest tripLikedItemRequest(){ + return new TripLikedItemRequest(List.of(1L, 2L, 3L, 4L)); + } + + public static TripSurveyResponse tripSurveyResponse(){ + return new TripSurveyResponse( + 20L, + 10L, + 30L, + 40L, + 4L, + 2L, + 4L, + 3L, + 8L, + 3L + + ); + } + + public static TripMember savedTripMember(Member member, Trip trip){ + return TripMember.builder() + .member(member) + .trip(trip) + .tripAuthority(TripAuthority.WRITE) + .build(); + } + + public static TripLikedItem saveTripLikedItem(Trip trip,TourItem tourItem){ + return TripLikedItem.builder() + .id(1L) + .trip(trip) + .tourItem(tourItem) + .build(); + } + + public static TripLikedItemPreference saveTripLikedItemPreference(TripMember tripMember,TripLikedItem tripLikedItem){ + return TripLikedItemPreference.builder() + .id(1L) + .prefer(true) + .notPrefer(false) + .tripMember(tripMember) + .tripLikedItem(tripLikedItem) + .build(); + + + } + + + +} diff --git a/src/test/java/org/tenten/tentenbe/config/MockAwsS3Config.java b/src/test/java/org/tenten/tentenbe/config/MockAwsS3Config.java new file mode 100644 index 00000000..4da08fb4 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/config/MockAwsS3Config.java @@ -0,0 +1,19 @@ +package org.tenten.tentenbe.config; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3Client; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.tenten.tentenbe.config.S3Config; + +//@Configuration +public class MockAwsS3Config extends S3Config { + @Bean + @Primary + @Override + public AmazonS3Client amazonS3Client() { + return Mockito.mock(AmazonS3Client.class); + } +} \ No newline at end of file diff --git a/src/test/java/org/tenten/tentenbe/config/WithMockCustomUser.java b/src/test/java/org/tenten/tentenbe/config/WithMockCustomUser.java new file mode 100644 index 00000000..d9b3ec01 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/config/WithMockCustomUser.java @@ -0,0 +1,17 @@ +package org.tenten.tentenbe.config; + +import org.springframework.security.test.context.support.WithSecurityContext; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +@WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class) +public @interface WithMockCustomUser { + long customUserId() default 1; + + String customUserName() default "customUserName"; + + String customUserPassword() default "customUserPassword"; + +} \ No newline at end of file diff --git a/src/test/java/org/tenten/tentenbe/config/WithMockCustomUserSecurityContextFactory.java b/src/test/java/org/tenten/tentenbe/config/WithMockCustomUserSecurityContextFactory.java new file mode 100644 index 00000000..ba649d72 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/config/WithMockCustomUserSecurityContextFactory.java @@ -0,0 +1,28 @@ +package org.tenten.tentenbe.config; + +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.test.context.support.WithSecurityContextFactory; +import org.tenten.tentenbe.domain.auth.dto.request.SignUpRequest; +import org.tenten.tentenbe.domain.member.model.Member; + +import java.util.Arrays; + +import static org.tenten.tentenbe.global.common.enums.LoginType.EMAIL; +import static org.tenten.tentenbe.global.common.enums.UserAuthority.ROLE_USER; + +public class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory { + @Override + public SecurityContext createSecurityContext(WithMockCustomUser customUser) { + SecurityContext context = SecurityContextHolder.createEmptyContext(); + Member principal = new SignUpRequest(customUser.customUserName(),customUser.customUserPassword()).toEntity(customUser.customUserPassword(), EMAIL, ROLE_USER); + Authentication auth = new UsernamePasswordAuthenticationToken(customUser.customUserId(), principal.getPassword(), Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"))); + context.setAuthentication(auth); + return context; + } +} + + diff --git a/src/test/java/org/tenten/tentenbe/domain/auth/controller/AuthControllerTest.java b/src/test/java/org/tenten/tentenbe/domain/auth/controller/AuthControllerTest.java new file mode 100644 index 00000000..a19ee8cb --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/auth/controller/AuthControllerTest.java @@ -0,0 +1,113 @@ +package org.tenten.tentenbe.domain.auth.controller; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.tenten.tentenbe.common.ControllerTest; +import org.tenten.tentenbe.common.fixture.AuthFixture; +import org.tenten.tentenbe.config.WithMockCustomUser; +import org.tenten.tentenbe.domain.auth.dto.response.CheckResponse; +import org.tenten.tentenbe.domain.auth.service.AuthService; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +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.*; +import static org.tenten.tentenbe.global.common.constant.JwtConstants.ACCESS_TOKEN_EXPIRE_TIME; +import static org.tenten.tentenbe.global.common.constant.JwtConstants.BEARER_TYPE; + +public class AuthControllerTest extends ControllerTest { + + @MockBean + private AuthService authService; + + @Test + @DisplayName("일반 회원가입 성공") + public void signUpSuccess() throws Exception { + + //given + given(authService.signUp(any(), any())).willReturn(AuthFixture.signUpResponse()); + + mockMvc.perform(post("/api/auth/signup") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(AuthFixture.signUpRequest()))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.memberId").value(1L)) + .andExpect(jsonPath("$.data.email").value("test@gmail.com")) + .andExpect(jsonPath("$.data.nickName").value("test")) + .andDo(print()); + } + + @Test + @DisplayName("회원가입시 닉네임 중복 확인") + public void checkNickName() throws Exception { + //given + given(authService.nicknameCheck(any())).willReturn(new CheckResponse(true)); + + mockMvc.perform(get("/api/auth/nicknames/check/test") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andDo(print()); + } + + @Test + @DisplayName("회원가입시 이메일 중복 확인") + public void checkEmailAddress() throws Exception { + //given + given(authService.emailCheck(any())).willReturn(new CheckResponse(true)); + + mockMvc.perform(get("/api/auth/emails/check/test@gmail.com") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andDo(print()); + } + + @Test + @DisplayName("일반 이메일 로그인") + public void logInWithEmail() throws Exception { + + //given + given(authService.login(any(), any())).willReturn(AuthFixture.loginResponse()); + + mockMvc.perform(post("/api/auth/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(AuthFixture.signUpResponse()))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.memberDto.id").value(1L)) + .andExpect(jsonPath("$.data.memberDto.nickName").value("test")) + .andExpect(jsonPath("$.data.memberDto.email").value("test@gmail.com")) + .andExpect(jsonPath("$.data.tokenInfo.accessToken").value("c2lsdmVfijhtroiehJ432NwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQtc2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQK")) + .andExpect(jsonPath("$.data.tokenInfo.grantType").value(BEARER_TYPE)) + .andExpect(jsonPath("$.data.tokenInfo.accessTokenExpiresIn").value(ACCESS_TOKEN_EXPIRE_TIME)) + .andDo(print()); + } + + + @Test + @DisplayName("소셜 카카오 로그인") + public void signUpSuccessWithKakao() throws Exception { + //given + //TODO: 카카오 로그인 코드 완료 후 재 검토 + mockMvc.perform(post("/api/auth/login/kakao") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(AuthFixture.loginRequest()))) + .andExpect(status().isConflict()) + .andDo(print()); + } + + @Test + @WithMockCustomUser + @DisplayName("로그아웃 성공") + public void logOutSuccess() throws Exception { + //given + mockMvc.perform(post("/api/auth/logout")) + .andExpect(status().isOk()) + .andExpect(content().string("LOGOUT!")) + .andDo(print()); + } + +} diff --git a/src/test/java/org/tenten/tentenbe/domain/auth/repository/AuthRepositoryTest.java b/src/test/java/org/tenten/tentenbe/domain/auth/repository/AuthRepositoryTest.java new file mode 100644 index 00000000..a336f90a --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/auth/repository/AuthRepositoryTest.java @@ -0,0 +1,66 @@ +package org.tenten.tentenbe.domain.auth.repository; + + +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +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.test.context.ActiveProfiles; +import org.tenten.tentenbe.common.RepositoryTest; +import org.tenten.tentenbe.common.fixture.AuthFixture; +import org.tenten.tentenbe.domain.member.model.Member; +import org.tenten.tentenbe.domain.member.repository.MemberRepository; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.tenten.tentenbe.global.common.enums.UserAuthority.ROLE_USER; + +public class AuthRepositoryTest extends RepositoryTest { + + @Test + @DisplayName("회원 저장 성공") + public void memberSave() { + + Member member = memberRepository.save(AuthFixture.newMember()); + + assertThat(member.getId()).isNotNull(); + assertThat(member.getEmail()).isEqualTo("test@gmail.com"); + assertThat(member.getUserAuthority()).isEqualTo(ROLE_USER); + } + + @Test + @DisplayName("회원 아이디로 회원 정보 조회 성공") + public void memberFindById() { + + Member saveMember = memberRepository.save(AuthFixture.newMember()); + Optional findMember = memberRepository.findById(saveMember.getId()); + + assertThat(findMember).isNotNull(); + assertThat(saveMember.getId()).isEqualTo(findMember.get().getId()); + } + + @Test + @DisplayName("존재하는 이메일 확인") + public void existsByEmail() { + + Member saveMember = memberRepository.save(AuthFixture.newMember()); + Boolean checkEmail = memberRepository.existsByEmail(saveMember.getEmail()); + + assertThat(checkEmail).isEqualTo(true); + } + + @Test + @DisplayName("존재하는 닉네임 확인") + public void existsByNickname() { + + Member saveMember = memberRepository.save(AuthFixture.newMember()); + Boolean checkNickName = memberRepository.existsByNickname(saveMember.getNickname()); + + assertThat(checkNickName).isEqualTo(true); + } + +} diff --git a/src/test/java/org/tenten/tentenbe/domain/auth/service/AuthServiceTest.java b/src/test/java/org/tenten/tentenbe/domain/auth/service/AuthServiceTest.java new file mode 100644 index 00000000..25ae8082 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/auth/service/AuthServiceTest.java @@ -0,0 +1,113 @@ +package org.tenten.tentenbe.domain.auth.service; + + +import jakarta.servlet.http.HttpServletResponse; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.tenten.tentenbe.common.ServiceTest; +import org.tenten.tentenbe.common.fixture.AuthFixture; +import org.tenten.tentenbe.config.WithMockCustomUser; +import org.tenten.tentenbe.domain.auth.dto.request.SignUpRequest; +import org.tenten.tentenbe.domain.auth.dto.response.CheckResponse; +import org.tenten.tentenbe.domain.auth.dto.response.LoginResponse; +import org.tenten.tentenbe.domain.auth.dto.response.SignUpResponse; +import org.tenten.tentenbe.domain.member.model.Member; +import org.tenten.tentenbe.domain.member.repository.MemberRepository; +import org.tenten.tentenbe.global.common.enums.LoginType; +import org.tenten.tentenbe.global.common.enums.UserAuthority; +import org.tenten.tentenbe.global.security.jwt.repository.RefreshTokenRepository; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; + +public class AuthServiceTest extends ServiceTest { + + @InjectMocks + private AuthService authService; + @Mock + private MemberRepository memberRepository; + @Mock + private BCryptPasswordEncoder passwordEncoder; + @Mock + private RefreshTokenRepository refreshTokenRepository; + @Mock + private HttpServletResponse httpServletResponse; + + @Test + @DisplayName("일반 회원가입 성공") + public void signUpSuccess() throws Exception { + + SignUpRequest signUpRequest = new SignUpRequest("test@gmail.com", "qwerty1234"); + Member newMember = signUpRequest.toEntity(passwordEncoder.encode(signUpRequest.password()), LoginType.EMAIL, UserAuthority.ROLE_USER); + + given(memberRepository.existsByEmail(any())).willReturn(false); + given(memberRepository.save(any())).willReturn(newMember); + given(memberRepository.findByEmail(any())).willReturn(Optional.ofNullable(AuthFixture.newMember())); + given(refreshTokenRepository.save(any())).willReturn(AuthFixture.refreshToken()); + given(passwordEncoder.encode(any())).willReturn("$10$ygrAExVYmFTkZn2d0.Pk3Ot5CNZwIBjZH5f.WW0AnUq4w4PtBi9Nm"); + + + //TODO:: 회원가입시 "this.authenticationManagerBuilder" is null 오류해결중 + + SignUpResponse signUpResponse = authService.signUp(AuthFixture.signUpRequest(), httpServletResponse); + assertThat(signUpResponse).extracting("memberId", "email", "nickName") + .containsExactly(1L, "test@gmail.com", "test"); + } + + @Test + @DisplayName("로그인시 토큰 발급 성공") + public void tokenIssuedSuccess() throws Exception { + +// TODO: "this.authenticationManagerBuilder" is null 오류 + + given(memberRepository.findById(any())).willReturn(Optional.ofNullable(AuthFixture.newMember())); + given(memberRepository.existsByEmail(any())).willReturn(false); + given(memberRepository.save(any())).willReturn(AuthFixture.newMember()); + + LoginResponse loginResponse = authService.login(AuthFixture.loginRequest(), httpServletResponse); + + assertNotNull(loginResponse); + + } + + @Test + @WithMockCustomUser() + @DisplayName("로그아웃 성공") + public void logOutSuccess() throws Exception { + + //TODO: There is no PasswordEncoder mapped for the id "null" 오류 + } + + @Test + @DisplayName("회원가입시 이메일 중복 확인") + public void checkEmailAddress() throws Exception { + given(memberRepository.existsByEmail(any(String.class))).willReturn(true); + CheckResponse checkResponse = authService.emailCheck("test@gmail.com"); + assertThat(checkResponse.exists()).isTrue(); + } + + @Test + @DisplayName("회원가입시 닉네임 중복 확인") + public void checkNickName() throws Exception { + given(memberRepository.existsByNickname(any(String.class))).willReturn(false); + CheckResponse checkResponse = authService.nicknameCheck("test2"); + assertThat(checkResponse.exists()).isFalse(); + + } + + + @Test + @DisplayName("소셜 카카오 로그인") + public void signUpSuccessWithKakao() throws Exception { + //TODO:구현예정 + } + + +} diff --git a/src/test/java/org/tenten/tentenbe/domain/comment/controller/CommentControllerTest.java b/src/test/java/org/tenten/tentenbe/domain/comment/controller/CommentControllerTest.java new file mode 100644 index 00000000..ea4bc757 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/comment/controller/CommentControllerTest.java @@ -0,0 +1,101 @@ +package org.tenten.tentenbe.domain.comment.controller; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.tenten.tentenbe.common.ControllerTest; +import org.tenten.tentenbe.config.WithMockCustomUser; +import org.tenten.tentenbe.domain.comment.exception.CommentException; +import org.tenten.tentenbe.domain.comment.service.CommentService; +import org.tenten.tentenbe.domain.member.repository.MemberRepository; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.willDoNothing; +import static org.mockito.Mockito.doThrow; +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; +import static org.tenten.tentenbe.common.fixture.CommentFixture.*; + +public class CommentControllerTest extends ControllerTest { + @MockBean + private CommentService commentService; + + @Test + @WithMockCustomUser + @DisplayName("댓글 작성 성공") + public void createCommentSuccess() throws Exception { + + given(commentService.createComment(any(), any())).willReturn(commentInfo()); + + mockMvc.perform(post("/api/comments") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(commentCreateRequest()))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.content").value("comment test content")) + .andExpect(jsonPath("$.data.authorNickname").value("comment Nick name")) + .andExpect(jsonPath("$.data.authorProfileImageUrl").value("profile image url")) + .andDo(print()); + } + + @Test + @WithMockCustomUser + @DisplayName("댓글 수정 성공") + public void updateCommentSuccess() throws Exception { + given(commentService.updateComment(any(),any(),any())).willReturn(commentInfo()); + + mockMvc.perform(put("/api/comments/1") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(commentUpdateRequest()))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.content").value("comment test content")) + .andExpect(jsonPath("$.data.authorNickname").value("comment Nick name")) + .andExpect(jsonPath("$.data.authorProfileImageUrl").value("profile image url")) + .andDo(print()); + } + + @Test + @WithMockCustomUser + @DisplayName("리뷰 삭제 성공") + public void deleteReviewSuccess() throws Exception { + + willDoNothing().given(commentService).deleteComment(any(),any()); + + mockMvc.perform(delete("/api/comments/1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").value("DELETED")) + .andDo(print()); + } + @Test + @WithMockCustomUser() + @DisplayName("리뷰 수정시 권한이 없을경우 401 에러 발생") + public void anonymousUpdateFail() throws Exception { + + given(commentService.updateComment(any(), any(), any())) + .willThrow(new CommentException("댓글 수정 권한이 없습니다.", HttpStatus.UNAUTHORIZED)); + + mockMvc.perform(put("/api/comments/1") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(commentUpdateRequest()))) + .andExpect(status().isUnauthorized()) + .andDo(print()); + } + + @Test + @WithMockCustomUser() + @DisplayName("리뷰 삭제시 권한이 없을경우 401 에러 발생") + public void anonymousDeleteFail() throws Exception { + + doThrow(new CommentException("댓글 수정 권한이 없습니다.", HttpStatus.UNAUTHORIZED)) + .when(commentService).deleteComment(any(), any()); + + mockMvc.perform(delete("/api/comments/1")) + .andExpect(status().isUnauthorized()) + .andDo(print()); + } + +} diff --git a/src/test/java/org/tenten/tentenbe/domain/comment/repository/CommentRepositoryTest.java b/src/test/java/org/tenten/tentenbe/domain/comment/repository/CommentRepositoryTest.java new file mode 100644 index 00000000..115427ff --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/comment/repository/CommentRepositoryTest.java @@ -0,0 +1,143 @@ +package org.tenten.tentenbe.domain.comment.repository; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.tenten.tentenbe.common.ControllerTest; +import org.tenten.tentenbe.common.RepositoryTest; +import org.tenten.tentenbe.config.WithMockCustomUser; +import org.tenten.tentenbe.domain.comment.model.Comment; +import org.tenten.tentenbe.domain.member.model.Member; +import org.tenten.tentenbe.domain.review.dto.request.ReviewCreateRequest; +import org.tenten.tentenbe.domain.review.dto.request.ReviewUpdateRequest; +import org.tenten.tentenbe.domain.review.dto.response.TourKeywordInfo; +import org.tenten.tentenbe.domain.review.model.Keyword; +import org.tenten.tentenbe.domain.review.model.Review; +import org.tenten.tentenbe.domain.review.service.ReviewService; +import org.tenten.tentenbe.domain.tour.model.TourItem; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doNothing; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +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 static org.tenten.tentenbe.common.fixture.AuthFixture.newBasicMember; +import static org.tenten.tentenbe.common.fixture.CommentFixture.commentResponse; +import static org.tenten.tentenbe.common.fixture.CommentFixture.saveComment; +import static org.tenten.tentenbe.common.fixture.MemberFixture.tourItem; +import static org.tenten.tentenbe.common.fixture.ReviewFixture.*; + +public class CommentRepositoryTest extends RepositoryTest { + + @Autowired + private CommentRepository commentRepository; + @Test + @DisplayName("코멘트 저장이 가능하다.") + public void saveCommentSuccess() { + //given + Member savedMember = memberRepository.save(newBasicMember()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + Review savedReview = reviewRepository.save(saveReview(savedTourItem,savedMember)); + String content = "can create comment"; + + //when + Comment comment = saveComment(content,savedReview,savedMember); + Comment savedComment = commentRepository.save(comment); + //then + assertThat(content).isEqualTo(savedComment.getContent()); + assertThat(comment).isEqualTo(savedComment); + } + + @Test + @DisplayName("코멘트 조회가 가능하다.") + public void findCommentSuccess() { + //given + Member savedMember = memberRepository.save(newBasicMember()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + Review savedReview = reviewRepository.save(saveReview(savedTourItem,savedMember)); + String content = "can create comment"; + + Comment comment = saveComment(content,savedReview,savedMember); + Comment comment2 = saveComment(content,savedReview,savedMember); + Comment comment3 = saveComment(content,savedReview,savedMember); + + commentRepository.saveAll(List.of(comment,comment2,comment3)); + //when + List findAllByComment = commentRepository.findAll(); + + //then + assertThat(findAllByComment.size()).isEqualTo(3); + } + + @Test + @DisplayName("코멘트 저장 후 리뷰 조회가 가능하다.") + public void reviewCanFindComment() { + //given + Member savedMember = memberRepository.save(newBasicMember()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + Review savedReview = reviewRepository.save(saveReview(savedTourItem,savedMember)); + String content = "can create comment"; + + Comment comment = saveComment(content,savedReview,savedMember); + + Comment savedComment = commentRepository.save(comment); + //when + Optional findAllByComment = commentRepository.findById(savedComment.getId()); + + //then + assertNotNull(findAllByComment); + assertThat(findAllByComment.get().getReview().getContent()).isEqualTo(savedReview.getContent()); + assertThat(findAllByComment.get().getReview()).isEqualTo(savedReview); + } + + @Test + @DisplayName("코멘트 수정이 가능하다.") + public void updateCommentSuccess() { + //given + Member savedMember = memberRepository.save(newBasicMember()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + Review savedReview = reviewRepository.save(saveReview(savedTourItem,savedMember)); + String content = "can create comment"; + String updateContent = "comment is updated"; + + Comment comment = saveComment(content,savedReview,savedMember); + Comment savedComment = commentRepository.save(comment); + savedComment.UpdateComment(updateContent); + //when + Optional findByComment = commentRepository.findById(savedComment.getId()); + + //then + assertNotNull(findByComment); + assertThat(findByComment.get().getContent()).isEqualTo(updateContent); + } + + @Test + @DisplayName("코멘트 삭제가 가능하다.") + public void deleteCommentSuccess() { + //given + Member savedMember = memberRepository.save(newBasicMember()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + Review savedReview = reviewRepository.save(saveReview(savedTourItem,savedMember)); + String content = "can create comment"; + + Comment comment = saveComment(content,savedReview,savedMember); + + //when then + Comment savedComment = commentRepository.save(comment); + assertThat(commentRepository.findAll().size()).isEqualTo(1); + + commentRepository.deleteById(savedComment.getId()); + assertThat(commentRepository.findAll().size()).isEqualTo(0); + } +} diff --git a/src/test/java/org/tenten/tentenbe/domain/comment/service/CommentServiceTest.java b/src/test/java/org/tenten/tentenbe/domain/comment/service/CommentServiceTest.java index 1e43771f..e85b0450 100644 --- a/src/test/java/org/tenten/tentenbe/domain/comment/service/CommentServiceTest.java +++ b/src/test/java/org/tenten/tentenbe/domain/comment/service/CommentServiceTest.java @@ -1,39 +1,146 @@ package org.tenten.tentenbe.domain.comment.service; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.transaction.annotation.Transactional; -import org.tenten.tentenbe.domain.comment.dto.request.CommentCreateRequest; +import org.tenten.tentenbe.common.ServiceTest; +import org.tenten.tentenbe.config.WithMockCustomUser; +import org.tenten.tentenbe.domain.comment.dto.response.CommentInfo; +import org.tenten.tentenbe.domain.comment.exception.CommentException; import org.tenten.tentenbe.domain.comment.model.Comment; import org.tenten.tentenbe.domain.comment.repository.CommentRepository; -import org.tenten.tentenbe.domain.review.model.Review; +import org.tenten.tentenbe.domain.member.exception.MemberException; +import org.tenten.tentenbe.domain.member.repository.MemberRepository; +import org.tenten.tentenbe.domain.review.exception.ReviewException; +import org.tenten.tentenbe.domain.review.repository.ReviewRepository; -@Transactional -@ExtendWith(MockitoExtension.class) -class CommentServiceTest { +import java.util.Optional; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.BDDMockito.given; +import static org.springframework.http.HttpStatus.FORBIDDEN; +import static org.springframework.http.HttpStatus.NOT_FOUND; +import static org.tenten.tentenbe.common.fixture.AuthFixture.newBasicMember; +import static org.tenten.tentenbe.common.fixture.CommentFixture.*; +import static org.tenten.tentenbe.common.fixture.ReviewFixture.review; + + +class CommentServiceTest extends ServiceTest { @InjectMocks private CommentService commentService; - @Mock - CommentRepository commentRepository; + private CommentRepository commentRepository; + @Mock + private ReviewRepository reviewRepository; + @Mock + private MemberRepository memberRepository; + + + @Test + @DisplayName("댓글 생성시 리뷰가 없을 경우 NOT_FOUND 에러를 표시한다.") + public void notFoundReview(){ + given(reviewRepository.findById(anyLong())) + .willThrow(new ReviewException("해당 아이디로 존재하는 리뷰가 없습니다.", NOT_FOUND)); + + ReviewException exception = Assertions.assertThrows(ReviewException.class, () -> commentService.createComment(1L, commentCreateRequest())); + assertThat(NOT_FOUND).isEqualTo(exception.getErrorCode()); + } + + @Test + @DisplayName("사용자가 없을시 사용자 NOT_FOUND 에러를 표시한다.") + public void notFoundUser(){ + given(reviewRepository.findById(anyLong())).willReturn(Optional.ofNullable(review())); + given(memberRepository.findById(anyLong())) + .willThrow(new MemberException("주어진 아이디로 존재하는 멤버가 없습니다.", NOT_FOUND)); + + MemberException exception = Assertions.assertThrows(MemberException.class, () -> commentService.createComment(1L, commentCreateRequest())); + assertThat(NOT_FOUND).isEqualTo(exception.getErrorCode()); + } + + @Test + @DisplayName("댓글 수정시 댓글이 없을 경우 NOT_FOUND 에러를 표시한다.") + public void notFoundComment(){ + given(memberRepository.findById(anyLong())).willReturn(Optional.ofNullable(newBasicMember())); + given(commentRepository.findById(any())) + .willThrow(new CommentException("해당 댓글이 없습니다.", NOT_FOUND)); + + CommentException exception = Assertions.assertThrows(CommentException.class, () -> commentService.updateComment(1L,1L,commentUpdateRequest())); + assertThat(NOT_FOUND).isEqualTo(exception.getErrorCode()); + } @Test + @DisplayName("댓글 수정시 댓글이 없을 경우 NOT_FOUND 에러를 표시한다.") + public void noUpdatePermissionComment(){ + given(memberRepository.findById(anyLong())).willReturn(Optional.ofNullable(newBasicMember())); + given(commentRepository.findById(any())).willReturn(Optional.of(comment())); + + CommentException exception = Assertions.assertThrows(CommentException.class, () -> commentService.updateComment(1L,1L,commentUpdateRequest())); + assertThat(FORBIDDEN).isEqualTo(exception.getErrorCode()); + } + + @Test + @WithMockCustomUser + @DisplayName("댓글 삭제시 댓글이 없을경우 NOT_FOUND 에러를 표시한다.") + public void noDeletePermissionComment(){ + given(memberRepository.findById(anyLong())).willReturn(Optional.ofNullable(newBasicMember())); + given(commentRepository.findById(any())).willReturn(Optional.of(comment())); + + CommentException exception = Assertions.assertThrows(CommentException.class, () -> commentService.deleteComment(1L,1L)); + assertThat(FORBIDDEN).isEqualTo(exception.getErrorCode()); + } + + + @Test + @WithMockCustomUser @DisplayName("댓글 생성 성공") public void createCommentTest(){ - Review review = new Review(1L, 4.5, "좋은 여행", null, null); + Comment savedComment = saveComment(commentCreateRequest().content(), review(), newBasicMember()); + + given(reviewRepository.findById(anyLong())).willReturn(Optional.ofNullable(review())); + given(memberRepository.findById(anyLong())).willReturn(Optional.ofNullable(newBasicMember())); + given(commentRepository.save(any())).willReturn(savedComment); - CommentCreateRequest commentCreateRequest = new CommentCreateRequest( - "여행 즐거웠습니다. ", - review.getId() - ); + CommentInfo result = commentService.createComment(newBasicMember().getId(), commentCreateRequest()); + assertThat(result.authorNickname()).isEqualTo("nickNameTest"); + assertThat(result.content()).isEqualTo("success create comment"); + assertThat(result.authorProfileImageUrl()).isEqualTo("naver.com"); + assertThat(result.isAuthor()).isEqualTo(true); } + @Test + @WithMockCustomUser + @DisplayName("댓글 업데이트 성공") + public void updateCommentTest(){ + Comment savedComment = saveComment(commentCreateRequest().content(), review(), newBasicMember()); + + given(memberRepository.findById(anyLong())).willReturn(Optional.ofNullable(newBasicMember())); + given(commentRepository.findById(any())).willReturn(Optional.of(savedComment)); + + CommentInfo result = commentService.updateComment(newBasicMember().getId(), comment().getId(),commentUpdateRequest()); + + assertThat(result.authorNickname()).isEqualTo("nickNameTest"); + assertThat(result.content()).isEqualTo("update comment"); + assertThat(result.authorProfileImageUrl()).isEqualTo("naver.com"); + assertThat(result.isAuthor()).isEqualTo(true); + } + @Test + @WithMockCustomUser + @DisplayName("댓글 삭제 성공") + public void deleteCommentTest(){ + Comment savedComment = saveComment(commentCreateRequest().content(), review(), newBasicMember()); + + given(memberRepository.findById(anyLong())).willReturn(Optional.ofNullable(newBasicMember())); + given(commentRepository.findById(any())).willReturn(Optional.of(savedComment)); + + assertDoesNotThrow(() -> commentService.deleteComment(newBasicMember().getId(), comment().getId())); + } } \ No newline at end of file diff --git a/src/test/java/org/tenten/tentenbe/domain/liked/controller/LikesControllerTest.java b/src/test/java/org/tenten/tentenbe/domain/liked/controller/LikesControllerTest.java new file mode 100644 index 00000000..0dc8c677 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/liked/controller/LikesControllerTest.java @@ -0,0 +1,48 @@ +package org.tenten.tentenbe.domain.liked.controller; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.tenten.tentenbe.common.ControllerTest; +import org.tenten.tentenbe.config.WithMockCustomUser; +import org.tenten.tentenbe.domain.liked.service.LikedService; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.willDoNothing; +import static org.mockito.Mockito.doThrow; +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; + +public class LikesControllerTest extends ControllerTest { + @MockBean + private LikedService likedService; + + + @Test + @WithMockCustomUser + @DisplayName("좋아요 등록") + public void updateCommentSuccess() throws Exception { + + mockMvc.perform(post("/api/liked/1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").value("SUCCESS")) + .andDo(print()); + } + + @Test + @WithMockCustomUser + @DisplayName("좋아요 삭제") + public void deleteReviewSuccess() throws Exception { + + willDoNothing().given(likedService).cancelLikeTour(any(),any()); + + mockMvc.perform(delete("/api/liked/1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").value("DELETED")) + .andDo(print()); + } + +} diff --git a/src/test/java/org/tenten/tentenbe/domain/liked/repository/LikesRepositoryTest.java b/src/test/java/org/tenten/tentenbe/domain/liked/repository/LikesRepositoryTest.java new file mode 100644 index 00000000..04d4bbff --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/liked/repository/LikesRepositoryTest.java @@ -0,0 +1,56 @@ +package org.tenten.tentenbe.domain.liked.repository; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.tenten.tentenbe.common.RepositoryTest; +import org.tenten.tentenbe.domain.liked.model.LikedItem; +import org.tenten.tentenbe.domain.member.model.Member; +import org.tenten.tentenbe.domain.review.model.Review; +import org.tenten.tentenbe.domain.tour.model.TourItem; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.tenten.tentenbe.common.fixture.AuthFixture.newBasicMember; +import static org.tenten.tentenbe.common.fixture.MemberFixture.likedSaveItem; +import static org.tenten.tentenbe.common.fixture.MemberFixture.tourItem; +import static org.tenten.tentenbe.common.fixture.ReviewFixture.saveReview; + +public class LikesRepositoryTest extends RepositoryTest { + + @Autowired + LikedItemRepository likedItemRepository; + + @Test + @DisplayName("좋아요 추가가 가능하다.") + public void testTourItemRepository() { + //given + Member savedMember = memberRepository.save(newBasicMember()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + Review savedReview = reviewRepository.save(saveReview(savedTourItem,savedMember)); + LikedItem savedLikedItem = likedItemRepository.save(likedSaveItem(savedMember,savedTourItem)); + + //when + LikedItem likedItem = likedItemRepository.save(savedLikedItem); + //then + assertThat(likedItem.getMember()).isEqualTo(savedMember); + assertThat(likedItem.getTourItem()).isEqualTo(savedTourItem); + } + + @Test + @DisplayName("좋아요 삭제가 가능하다.") + public void testLikedItemRepository() { + //given + Member savedMember = memberRepository.save(newBasicMember()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + Review savedReview = reviewRepository.save(saveReview(savedTourItem,savedMember)); + LikedItem savedLikedItem = likedItemRepository.save(likedSaveItem(savedMember,savedTourItem)); + + //when + LikedItem likedItem = likedItemRepository.save(savedLikedItem); + assertThat(likedItemRepository.findAll().size()).isEqualTo(1); + //then + likedItemRepository.deleteById(likedItem.getId()); + assertThat(likedItemRepository.findAll().size()).isEqualTo(0); + + } +} \ No newline at end of file diff --git a/src/test/java/org/tenten/tentenbe/domain/liked/service/LikesServiceTest.java b/src/test/java/org/tenten/tentenbe/domain/liked/service/LikesServiceTest.java new file mode 100644 index 00000000..1716eee7 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/liked/service/LikesServiceTest.java @@ -0,0 +1,65 @@ +package org.tenten.tentenbe.domain.liked.service; + +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.tenten.tentenbe.common.ServiceTest; +import org.tenten.tentenbe.domain.liked.repository.LikedItemRepository; +import org.tenten.tentenbe.domain.member.repository.MemberRepository; +import org.tenten.tentenbe.domain.tour.repository.TourItemRepository; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.tenten.tentenbe.common.fixture.AuthFixture.newBasicMember; +import static org.tenten.tentenbe.common.fixture.MemberFixture.likedItem; +import static org.tenten.tentenbe.common.fixture.MemberFixture.tourItem; + +public class LikesServiceTest extends ServiceTest { + @InjectMocks + private LikedService likedService; + @Mock + private MemberRepository memberRepository; + @Mock + private TourItemRepository tourItemRepository; + @Mock + private LikedItemRepository likedItemRepository; + + + + @Test + public void likeTourSuccess() { + given(memberRepository.findById(any())).willReturn(Optional.of(newBasicMember())); + given(tourItemRepository.findById(any())).willReturn(Optional.of(tourItem())); + given(likedItemRepository.findByMemberAndTourItem(any(), any())).willReturn(Optional.empty()); + + assertDoesNotThrow(() -> likedService.likeTour(tourItem().getId(), newBasicMember().getId())); + + // 메서드 검증 + verify(memberRepository, times(1)).findById(newBasicMember().getId()); + verify(tourItemRepository, times(1)).findById(tourItem().getId()); + verify(likedItemRepository, times(1)).findByMemberAndTourItem(any(), any()); + verify(likedItemRepository, times(1)).save(any()); + } + + @Test + public void cancelLikeTourSuccess() { + + given(memberRepository.findById(any())).willReturn(Optional.of(newBasicMember())); + given(tourItemRepository.findById(any())).willReturn(Optional.of(tourItem())); + given(likedItemRepository.findByMemberAndTourItem(any(), any())).willReturn(Optional.of(likedItem())); + + // 테스트 수행 + assertDoesNotThrow(() -> likedService.cancelLikeTour(tourItem().getId(), newBasicMember().getId())); + + // 해당 메서드들이 호출되었는지 검증 + verify(memberRepository, times(1)).findById(newBasicMember().getId()); + verify(tourItemRepository, times(1)).findById(tourItem().getId()); + verify(likedItemRepository, times(1)).findByMemberAndTourItem(any(), any()); + verify(likedItemRepository, times(1)).delete(any()); + } +} diff --git a/src/test/java/org/tenten/tentenbe/domain/member/controller/MemberControllerTest.java b/src/test/java/org/tenten/tentenbe/domain/member/controller/MemberControllerTest.java new file mode 100644 index 00000000..f804579c --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/member/controller/MemberControllerTest.java @@ -0,0 +1,175 @@ +package org.tenten.tentenbe.domain.member.controller; + + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.http.MediaType; +import org.tenten.tentenbe.common.ControllerTest; +import org.tenten.tentenbe.config.WithMockCustomUser; +import org.tenten.tentenbe.domain.member.dto.request.MemberUpdateRequest; +import org.tenten.tentenbe.domain.member.dto.request.PasswordUpdateRequest; +import org.tenten.tentenbe.domain.member.dto.request.SurveyUpdateRequest; +import org.tenten.tentenbe.domain.member.dto.response.MemberDetailResponse; +import org.tenten.tentenbe.domain.member.dto.response.MemberUpdateResponse; +import org.tenten.tentenbe.domain.member.model.Member; +import org.tenten.tentenbe.domain.member.service.MemberService; +import org.tenten.tentenbe.domain.review.dto.response.MemberReviewResponse; +import org.tenten.tentenbe.domain.tour.dto.response.TourSimpleResponse; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +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; +import static org.tenten.tentenbe.common.fixture.AuthFixture.*; +import static org.tenten.tentenbe.common.fixture.MemberFixture.survey; +import static org.tenten.tentenbe.common.fixture.MemberFixture.tourItem; +import static org.tenten.tentenbe.common.fixture.ReviewFixture.review; + +public class MemberControllerTest extends ControllerTest { + + @MockBean + private MemberService memberService; + + @Test + @WithMockCustomUser + @DisplayName("나의 관심 여행지 조회") + public void myFavoriteToursSuccess() throws Exception { + + List tourSimpleResponse = List.of(TourSimpleResponse.fromEntity(tourItem())); + Pageable pageable = PageRequest.of(0, 10); + + given(memberService.getTours(any(), any())).willReturn(new PageImpl<>(tourSimpleResponse, pageable, 1)); + mockMvc.perform(get("/api/member/tours?page=1&size=10")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.content.[0].id").value(1L)) + .andExpect(jsonPath("$.data.content.[0].contentTypeId").value(1L)) + .andExpect(jsonPath("$.data.content.[0].title").value("test title")) + .andExpect(jsonPath("$.data.content.[0].reviewCount").value(10L)) + .andExpect(jsonPath("$.data.content.[0].likedCount").value(20L)) + .andDo(print()); + } + + @Test + @WithMockCustomUser + @DisplayName("나의 리뷰 조회") + public void getReviewsSuccess() throws Exception { + + List memberReviewResponses = List.of(MemberReviewResponse.fromEntity(review())); + Pageable pageable = PageRequest.of(0, 10); + + given(memberService.getReviews(any(), any())).willReturn(new PageImpl<>(memberReviewResponses, pageable, 1)); + mockMvc.perform(get("/api/member/reviews?page=1&size=10")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.content.[0].reviewId").value(1L)) + .andExpect(jsonPath("$.data.content.[0].authorNickname").value("nickNameTest")) + .andExpect(jsonPath("$.data.content.[0].rating").value(20.5)) + .andExpect(jsonPath("$.data.content.[0].content").value("hello world")) + .andExpect(jsonPath("$.data.content.[0].commentCount").value(0)) + .andDo(print()); + } + + @Test + @WithMockCustomUser + @DisplayName("회원 정보 조회") + public void getMemberInfoSuccess() throws Exception { + MemberDetailResponse memberDetailResponse = MemberDetailResponse.fromEntity(newBasicMember()); + + given(memberService.getMemberInfo(any())).willReturn(memberDetailResponse); + mockMvc.perform(get("/api/member")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.loginType").value("EMAIL")) + .andExpect(jsonPath("$.data.nickname").value("nickNameTest")) + .andExpect(jsonPath("$.data.profileImageUrl").value("naver.com")) + .andExpect(jsonPath("$.data.email").value("test@gmail.com")) + .andExpect(jsonPath("$.data.ageType").value("TEENAGER")) + .andDo(print()); + + } + + @Test + @WithMockCustomUser + @DisplayName("회원 정보 수정") + public void updateMemberSuccess() throws Exception { + + MemberUpdateResponse memberUpdateResponse = MemberUpdateResponse.fromEntity(updateMember()); + MemberUpdateRequest memberUpdateRequest = memberUpdateRequest(); + + given(memberService.updateMember(any(), any())).willReturn(memberUpdateResponse); + mockMvc.perform(put("/api/member") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(memberUpdateRequest))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.nickname").value("update my nickName")) + .andExpect(jsonPath("$.data.profileImageUrl").value("updateNaver.com")) + .andExpect(jsonPath("$.data.ageType").value("TEENAGER")) + .andExpect(jsonPath("$.data.genderType").value("DEFAULT")) + .andDo(print()); + } + + @Test + @WithMockCustomUser + @DisplayName("비밀번호 수정") + public void updatePasswordSuccess() throws Exception { + PasswordUpdateRequest passwordUpdateRequest = new PasswordUpdateRequest("changedPassword","newPassword"); + + mockMvc.perform(put("/api/member/password") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(passwordUpdateRequest))) + .andExpect(status().isOk()); + } + + @Test + @WithMockCustomUser() + @DisplayName("여행 취향 수정") + public void updateSurveySuccess() throws Exception { + SurveyUpdateRequest surveyUpdateRequest = new SurveyUpdateRequest(survey()); + + mockMvc.perform(put("/api/member/survey") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(surveyUpdateRequest))) + .andExpect(status().isOk()); + } + + @Test + @WithMockCustomUser + @DisplayName("회원 탈퇴") + public void deleteMemberSuccess() throws Exception { + + Member member = newMember(); + HttpServletRequest request = mock(HttpServletRequest.class); + HttpServletResponse response = mock(HttpServletResponse.class); + + doNothing().when(memberService).deleteMember(member.getId(), request, response); + + mockMvc.perform(delete("/api/member")) + .andExpect(status().isOk()); + + } + + @Test + @WithMockCustomUser + @DisplayName("이미지 업로드") + public void upLoadImageSuccess() throws Exception { + + //TODO:s3 모킹 코드 작성 예정 +// +// mockMvc.perform(post("/api/member") +// .contentType(MediaType.MULTIPART_FORM_DATA_VALUE) +// .contentType(MediaType.APPLICATION_JSON_VALUE) +// .content(objectMapper.writeValueAsBytes(any()))) +// .andExpect(status().isOk()); + + } +} diff --git a/src/test/java/org/tenten/tentenbe/domain/member/repository/MemberRepositoryTest.java b/src/test/java/org/tenten/tentenbe/domain/member/repository/MemberRepositoryTest.java new file mode 100644 index 00000000..7047c5ab --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/member/repository/MemberRepositoryTest.java @@ -0,0 +1,82 @@ +package org.tenten.tentenbe.domain.member.repository; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.tenten.tentenbe.common.RepositoryTest; +import org.tenten.tentenbe.domain.liked.model.LikedItem; +import org.tenten.tentenbe.domain.member.model.Member; +import org.tenten.tentenbe.domain.review.model.Review; +import org.tenten.tentenbe.domain.tour.model.TourItem; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.tenten.tentenbe.common.fixture.AuthFixture.newBasicMember; +import static org.tenten.tentenbe.common.fixture.MemberFixture.likedSaveItem; +import static org.tenten.tentenbe.common.fixture.MemberFixture.tourItem; +import static org.tenten.tentenbe.common.fixture.ReviewFixture.saveReview; + +public class MemberRepositoryTest extends RepositoryTest { + + @Test + @DisplayName("likedItemRepository 에서 회원을 조회할 수 있는지") + public void myFavoriteToursSuccess() throws Exception { + + Pageable pageable = PageRequest.of(0, 10); + + Member savedMember = memberRepository.save(newBasicMember()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + + LikedItem likedItem = likedSaveItem(savedMember,savedTourItem); + LikedItem savedLikedItem = likedItemRepository.save(likedItem); + + Page findLikedItem = likedItemRepository.findByMember(likedItem.getMember(),pageable); + + assertThat(savedLikedItem.getMember().getId()).isEqualTo(findLikedItem.get().toList().get(0).getMember().getId()); + assertThat(savedLikedItem.getMember().getEmail()).isEqualTo(findLikedItem.get().toList().get(0).getMember().getEmail()); + } + + @Test + @DisplayName("reviewRepository 에서 리뷰와 사용자 조회를 할 수 있는지") + public void getReviewsSuccess() throws Exception { + + Pageable pageable = PageRequest.of(0, 10); + Member savedMember = memberRepository.save(newBasicMember()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + + reviewRepository.save(saveReview(savedTourItem,savedMember)); + + Page findReview = reviewRepository.findReviewByCreatorId(savedMember.getId(), pageable); + + assertThat(savedMember.getId()).isEqualTo(findReview.get().toList().get(0).getCreator().getId()); + assertThat(savedMember.getId()).isEqualTo(findReview.get().toList().get(0).getCreator().getId()); + } + + @Nested + @DisplayName("memberRepository 에서") + class memberRepository { + @Test + @DisplayName("회원 조회가 가능한지") + public void findMemberSuccess() throws Exception { + Member savedMember = memberRepository.save(newBasicMember()); + Optional findMember = memberRepository.findById(savedMember.getId()); + assertThat(savedMember.getId()).isEqualTo(findMember.get().getId()); + } + + @Test + @DisplayName("회원 삭제가 가능한지") + public void deleteMemberSuccess() throws Exception { + Member savedMember = memberRepository.save(newBasicMember()); + memberRepository.delete(savedMember); + List memberList = memberRepository.findAll(); + assertThat(memberList.size()).isEqualTo(0); + + } + + } +} diff --git a/src/test/java/org/tenten/tentenbe/domain/member/service/MemberServiceTest.java b/src/test/java/org/tenten/tentenbe/domain/member/service/MemberServiceTest.java new file mode 100644 index 00000000..d7551e73 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/member/service/MemberServiceTest.java @@ -0,0 +1,182 @@ +package org.tenten.tentenbe.domain.member.service; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.tenten.tentenbe.common.ServiceTest; +import org.tenten.tentenbe.domain.liked.model.LikedItem; +import org.tenten.tentenbe.domain.liked.repository.LikedItemRepository; +import org.tenten.tentenbe.domain.member.dto.request.MemberUpdateRequest; +import org.tenten.tentenbe.domain.member.dto.request.PasswordUpdateRequest; +import org.tenten.tentenbe.domain.member.dto.request.SurveyUpdateRequest; +import org.tenten.tentenbe.domain.member.dto.response.MemberDetailResponse; +import org.tenten.tentenbe.domain.member.dto.response.MemberUpdateResponse; +import org.tenten.tentenbe.domain.member.model.Member; +import org.tenten.tentenbe.domain.member.repository.MemberRepository; +import org.tenten.tentenbe.domain.review.dto.response.MemberReviewResponse; +import org.tenten.tentenbe.domain.review.model.Review; +import org.tenten.tentenbe.domain.review.repository.ReviewRepository; +import org.tenten.tentenbe.domain.tour.dto.response.TourSimpleResponse; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.tenten.tentenbe.common.fixture.AuthFixture.*; +import static org.tenten.tentenbe.common.fixture.MemberFixture.serviceLikedItem; +import static org.tenten.tentenbe.common.fixture.MemberFixture.updateSurvey; +import static org.tenten.tentenbe.common.fixture.ReviewFixture.review; + +; +public class MemberServiceTest extends ServiceTest { + + @InjectMocks + private MemberService memberService; + @Mock + private MemberRepository memberRepository; + @Mock + private ReviewRepository reviewRepository; + @Mock + private LikedItemRepository likedItemRepository; + @Mock + private PasswordEncoder passwordEncoder; + + + @Test + @DisplayName("나의 관심 여행지 조회시 페이지 리스트로 반환한다. ") + public void myFavoriteToursSuccess() throws Exception { + Member member = newBasicMember(); + Pageable pageable = PageRequest.of(0, 10); + List likedItems = List.of(serviceLikedItem()); + Page likedItemPage = new PageImpl<>(likedItems, pageable, likedItems.size()); + + given(memberRepository.findById(member.getId())).willReturn(Optional.ofNullable(member)); + given(likedItemRepository.findByMember(any(), any())).willReturn(likedItemPage); + + Page tourSimpleResponses = memberService.getTours(1L, pageable); + + assertNotNull(tourSimpleResponses); + + assertThat(tourSimpleResponses.getContent()).usingRecursiveAssertion().isEqualTo( + likedItemPage.getContent().stream() + .map(likedItem -> TourSimpleResponse.fromEntity(likedItem.getTourItem())).toList() + ); + } + + @Test + @DisplayName("나의 리뷰 조회") + public void getReviewsSuccess() throws Exception { + + Member member = newBasicMember(); + Pageable pageable = PageRequest.of(0, 10); + PageRequest pageRequest = PageRequest.of(0, 10); + List reviewList = List.of(review()); + Page reviewPage = new PageImpl<>(reviewList, pageable, reviewList.size()); + + // getReview 에 멤버 조회가 빠져있음 + // given(memberRepository.findById(member.getId())).willReturn(Optional.ofNullable(member)); + given(reviewRepository.findReviewByCreatorId(any(), any())).willReturn(reviewPage); + + Page memberReviewResponse = memberService.getReviews(1L, pageRequest); + + assertNotNull(memberReviewResponse); + assertThat(memberReviewResponse.getContent()).usingRecursiveAssertion().isEqualTo( + reviewPage.getContent().stream() + .map(review -> MemberReviewResponse.fromEntity(review)).toList() + ); + + } + + @Test + @DisplayName("회원 정보 조회") + public void getMemberInfoSuccess() throws Exception { + + Member member = newBasicMember(); + given(memberRepository.findById(member.getId())).willReturn(Optional.ofNullable(member)); + assertThat(memberService.getMemberInfo(member.getId())).isEqualTo(MemberDetailResponse.fromEntity(member)); + } + + @Test + @DisplayName("회원 정보 수정") + public void updateMemberSuccess() throws Exception { + Member member = newBasicMember(); + + MemberUpdateResponse memberUpdateResponse = MemberUpdateResponse.fromEntity(updateMember()); + MemberUpdateRequest memberUpdateRequest = memberUpdateRequest(); + + given(memberRepository.findById(member.getId())).willReturn(Optional.ofNullable(member)); + + assertThat(memberService.updateMember(member.getId(), memberUpdateRequest)) + .extracting("nickname", "profileImageUrl") + .containsExactly("update my nickName", "updateNaver.com"); + + } + + @Test + @DisplayName("비밀번호 수정") + public void updatePasswordSuccess() throws Exception { + Member member = newBasicMember(); + PasswordUpdateRequest passwordUpdateRequest = new PasswordUpdateRequest("changedPassword","newPassword"); + + given(memberRepository.findById(member.getId())).willReturn(Optional.ofNullable(member)); + given(!passwordEncoder.matches(passwordUpdateRequest.password(), member.getPassword())).willReturn(true); + given(passwordEncoder.encode(any())).willReturn(passwordUpdateRequest.newPassword()); + + memberService.updatePassword(member.getId(), passwordUpdateRequest); + + assertThat(member.getPassword()).isEqualTo(passwordUpdateRequest.newPassword()); + + } + + @Test + @DisplayName("여행 취향 수정") + public void updateSurveySuccess() throws Exception { + Member member = newBasicMember(); + SurveyUpdateRequest surveyUpdateRequest = new SurveyUpdateRequest(updateSurvey()); + + given(memberRepository.findById(member.getId())).willReturn(Optional.ofNullable(member)); + + memberService.updateSurvey(member.getId(), surveyUpdateRequest); + + assertThat(member.getSurvey()).extracting("planning", "activeHours", "accommodation", "food", "tripStyle") + .containsExactly("철저하게", "아침형", "분위기", "음식", "액티비티"); + } + + @Test + @DisplayName("회원 탈퇴") + public void deleteMemberSuccess() throws Exception { + + Member member = newBasicMember(); + HttpServletRequest request = mock(HttpServletRequest.class); + HttpServletResponse response = mock(HttpServletResponse.class); + + given(memberRepository.findById(member.getId())).willReturn(Optional.ofNullable(member)); + + memberService.deleteMember(member.getId(), request, response); + + verify(memberRepository).delete(member); + } + + @Test + @DisplayName("이미지 업로드") + public void upLoadImageSuccess() throws Exception { + + //TODO:s3 모킹 +// + + + } +} diff --git a/src/test/java/org/tenten/tentenbe/domain/review/controller/ReviewControllerTest.java b/src/test/java/org/tenten/tentenbe/domain/review/controller/ReviewControllerTest.java new file mode 100644 index 00000000..32ccb6e5 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/review/controller/ReviewControllerTest.java @@ -0,0 +1,119 @@ +package org.tenten.tentenbe.domain.review.controller; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.tenten.tentenbe.common.ControllerTest; +import org.tenten.tentenbe.config.WithMockCustomUser; +import org.tenten.tentenbe.domain.review.dto.request.ReviewCreateRequest; +import org.tenten.tentenbe.domain.review.dto.request.ReviewUpdateRequest; +import org.tenten.tentenbe.domain.review.service.ReviewService; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.willDoNothing; +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; +import static org.tenten.tentenbe.common.fixture.CommentFixture.commentResponse; +import static org.tenten.tentenbe.common.fixture.ReviewFixture.*; + +public class ReviewControllerTest extends ControllerTest { + + @MockBean + private ReviewService reviewService; + + @Test + @WithMockCustomUser + @DisplayName("리뷰 작성") + public void createReviewSuccess() throws Exception { + + ReviewCreateRequest reviewCreateRequest = reviewCreateRequest(); + + given(reviewService.createReview(any(), any())).willReturn(reviewInfo()); + + mockMvc.perform(post("/api/reviews") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(reviewCreateRequest))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data").exists()) + .andExpect(jsonPath("$.data.reviewId").value(1L)) + .andExpect(jsonPath("$.data.authorNickname").value("nickNameTest")) + .andExpect(jsonPath("$.data.authorProfileImageUrl").value("naver.com")) + .andExpect(jsonPath("$.data.rating").value(20.5)) + .andExpect(jsonPath("$.data.content").value("hello world")) + .andExpect(jsonPath("$.data.content").value("hello world")); + } + + @Test + @WithMockCustomUser + @DisplayName("리뷰 수정") + public void updateReviewSuccess() throws Exception { + + ReviewUpdateRequest reviewUpdateRequest = reviewUpdateRequest(); + + given(reviewService.updateReview(any(),any(),any())).willReturn(reviewInfo()); + + mockMvc.perform(put("/api/reviews/1") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(reviewUpdateRequest))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data").exists()) + .andExpect(jsonPath("$.data.reviewId").value(1L)) + .andExpect(jsonPath("$.data.authorNickname").value("nickNameTest")) + .andExpect(jsonPath("$.data.authorProfileImageUrl").value("naver.com")) + .andExpect(jsonPath("$.data.rating").value(20.5)) + .andExpect(jsonPath("$.data.content").value("hello world")); + } + + @Test + @WithMockCustomUser + @DisplayName("리뷰 삭제") + public void deleteReviewSuccess() throws Exception { + + willDoNothing().given(reviewService).deleteReview(any(),any()); + + mockMvc.perform(delete("/api/reviews/1") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").value("DELETED")) + .andDo(print());; + } + + @Test + @WithMockCustomUser + @DisplayName("리뷰 댓글조회") + public void getReviewDetailSuccess() throws Exception { + + given(reviewService.getReviewComments(any(),any(),any())).willReturn(commentResponse()); + + mockMvc.perform(get("/api/reviews/1/comments?page=0&size=10") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data").exists()) + .andExpect(jsonPath("$.data.comments.content.[0].authorNickname").value("comment Nick name")) + .andExpect(jsonPath("$.data.comments.content.[0].authorProfileImageUrl").value("profile image url")) + .andExpect(jsonPath("$.data.comments.content.[0].content").value("comment test content")) + .andExpect(jsonPath("$.data.comments.content.[0].isAuthor").value(true)) + .andDo(print()); + } + + @Test + @WithMockCustomUser + @DisplayName("리뷰 키워드 조회") + public void getKeyWordSuccess() throws Exception { + given(reviewService.getKeywords(any())).willReturn(keywordResponse()); + + mockMvc.perform(get("/api/reviews/keywords?keywordType=DINING_KEYWORD") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data").exists()) + .andExpect(jsonPath("$.data.keywords.[0].content").value("save keyword content")) + .andExpect(jsonPath("$.data.keywords.[0].type").value("DINING_KEYWORD")) + .andDo(print()); + + } + +} diff --git a/src/test/java/org/tenten/tentenbe/domain/review/repository/ReviewRepositoryTest.java b/src/test/java/org/tenten/tentenbe/domain/review/repository/ReviewRepositoryTest.java new file mode 100644 index 00000000..4324fea8 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/review/repository/ReviewRepositoryTest.java @@ -0,0 +1,126 @@ +package org.tenten.tentenbe.domain.review.repository; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.tenten.tentenbe.common.RepositoryTest; +import org.tenten.tentenbe.domain.comment.model.Comment; +import org.tenten.tentenbe.domain.comment.repository.CommentRepository; +import org.tenten.tentenbe.domain.member.model.Member; +import org.tenten.tentenbe.domain.review.dto.response.TourKeywordInfo; +import org.tenten.tentenbe.domain.review.model.Keyword; +import org.tenten.tentenbe.domain.review.model.Review; +import org.tenten.tentenbe.domain.tour.model.TourItem; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.tenten.tentenbe.common.fixture.AuthFixture.newBasicMember; +import static org.tenten.tentenbe.common.fixture.CommentFixture.saveComment; +import static org.tenten.tentenbe.common.fixture.MemberFixture.tourItem; +import static org.tenten.tentenbe.common.fixture.ReviewFixture.*; + +public class ReviewRepositoryTest extends RepositoryTest { + + @Autowired + private CommentRepository commentRepository; + @Test + @DisplayName("리뷰 키워드 정보를 조회 할 수 있다. ") + public void getTourReviewsSuccess() { + TourItem savedTourItem = tourItemRepository.save(tourItem()); + Member savedMember = memberRepository.save(newBasicMember()); + Review savedReview = reviewRepository.save(saveReview(savedTourItem,savedMember)); + Keyword savedKeyword = keywordRepository.save(keyword()); + reviewKeywordRepository.save(saveReviewKeyword(savedReview,savedKeyword)); + + List result = keywordRepository.findKeywordInfoByTourItemIdAndKeywordType(savedTourItem.getId()); + + assertNotNull(result); + assertThat(result.get(0).content()).isEqualTo(savedKeyword.getContent()); + assertThat(result.get(0).type()).isEqualTo(savedKeyword.getType()); + } + + @Test + @DisplayName("리뷰를 저장 할 수 있다.") + public void findKeywordInfoSuccess() { + Member savedMember = memberRepository.save(newBasicMember()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + + Review savedReview = reviewRepository.save(saveReview(savedTourItem,savedMember)); + + + Optional findReview = reviewRepository.findById(savedReview.getId()); + + assertNotNull(savedReview); + assertThat(findReview.get()).isEqualTo(savedReview); + } + + @Test + @DisplayName("리뷰를 업데이트 할 수 있다.") + public void updateReviewSuccess() { + + Member savedMember = memberRepository.save(newBasicMember()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + + Review savedReview = reviewRepository.save(saveReview(savedTourItem,savedMember)); + + assertThat(savedReview.getContent()).isEqualTo("saved review"); + + Optional updateReview = reviewRepository.findById(savedReview.getId()); + + assertNotNull(savedReview); + + updateReview.get().updateContent("update contents"); + updateReview.get().updateRating(100D); + + assertThat(updateReview.get().getContent()).isEqualTo("update contents"); + assertThat(updateReview.get().getRating()).isEqualTo(100D); + + } + + @Test + @DisplayName("리뷰를 삭제할 수 있다.") + public void deleteReviewSuccess() { + + Member savedMember = memberRepository.save(newBasicMember()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + + Review savedReview = reviewRepository.save(saveReview(savedTourItem,savedMember)); + + assertThat(reviewRepository.findAll().size()).isEqualTo(1); + + reviewRepository.deleteById(savedReview.getId()); + + assertThat(reviewRepository.findAll().size()).isEqualTo(0); + } + + @Test + @DisplayName("리뷰에서 댓글 조회를 할 수 있다.") + public void getReviewComment(){ + Pageable pageable = PageRequest.of(0, 10); + Member savedMember = memberRepository.save(newBasicMember()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + Review savedReview = reviewRepository.save(saveReview(savedTourItem,savedMember)); + String content = "first comment"; + String content2 = "second comment"; + + Comment comment = saveComment(content,savedReview,savedMember); + Comment comment2 = saveComment(content2,savedReview,savedMember); + + commentRepository.saveAll(List.of(comment, comment2)); + + //when + Page commentPage = commentRepository.findCommentsByReviewId(savedReview.getId(), pageable); + + //then + assertThat(commentPage.getContent().size()).isEqualTo(2); + assertThat(commentPage.getContent().get(0).getContent()).isEqualTo("first comment"); + assertThat(commentPage.getContent().get(1).getContent()).isEqualTo("second comment"); + } + +} diff --git a/src/test/java/org/tenten/tentenbe/domain/review/service/ReviewServiceTest.java b/src/test/java/org/tenten/tentenbe/domain/review/service/ReviewServiceTest.java new file mode 100644 index 00000000..6b19d522 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/review/service/ReviewServiceTest.java @@ -0,0 +1,153 @@ +package org.tenten.tentenbe.domain.review.service; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.tenten.tentenbe.common.ServiceTest; +import org.tenten.tentenbe.domain.comment.dto.response.CommentResponse; +import org.tenten.tentenbe.domain.comment.model.Comment; +import org.tenten.tentenbe.domain.comment.repository.CommentRepository; +import org.tenten.tentenbe.domain.member.repository.MemberRepository; +import org.tenten.tentenbe.domain.review.dto.response.KeywordResponse; +import org.tenten.tentenbe.domain.review.dto.response.ReviewInfo; +import org.tenten.tentenbe.domain.review.dto.response.ReviewResponse; +import org.tenten.tentenbe.domain.review.model.Review; +import org.tenten.tentenbe.domain.review.repository.KeywordRepository; +import org.tenten.tentenbe.domain.review.repository.ReviewKeywordRepository; +import org.tenten.tentenbe.domain.review.repository.ReviewRepository; +import org.tenten.tentenbe.domain.tour.repository.TourItemRepository; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.tenten.tentenbe.common.fixture.AuthFixture.newBasicMember; +import static org.tenten.tentenbe.common.fixture.CommentFixture.commentCreateRequest; +import static org.tenten.tentenbe.common.fixture.CommentFixture.saveComment; +import static org.tenten.tentenbe.common.fixture.MemberFixture.tourItem; +import static org.tenten.tentenbe.common.fixture.ReviewFixture.*; + +public class ReviewServiceTest extends ServiceTest { + + @InjectMocks + private ReviewService reviewService; + @Mock + private ReviewRepository reviewRepository; + @Mock + private MemberRepository memberRepository; + @Mock + private TourItemRepository tourItemRepository; + @Mock + private KeywordRepository keywordRepository; + @Mock + private ReviewKeywordRepository reviewKeywordRepository; + @Mock + private CommentRepository commentRepository; + + @Test + @DisplayName("여행 리뷰 조회가 가능하다.") + public void getTourReviewSuccess() { + Pageable pageable = PageRequest.of(0, 10); + given(tourItemRepository.findById(any())).willReturn(Optional.of(tourItem())); + given(reviewRepository.findReviewByTourItemId(any(),any())).willReturn(new PageImpl<>(List.of(saveReview(tourItem(),newBasicMember())), pageable, tourItem().getReviewTotalCount())); + given(keywordRepository.findKeywordInfoByTourItemIdAndKeywordType(any())).willReturn(List.of(tourKeywordInfo())); + + ReviewResponse result = reviewService.getTourReviews(tourItem().getReviewTotalCount(), pageable, newBasicMember().getId()); + + assertNotNull(result); + assertThat(result.reviewInfos().getContent().get(0).reviewId()).isEqualTo(1L); + assertThat(result.reviewInfos().getContent().get(0).authorNickname()).isEqualTo("nickNameTest"); + assertThat(result.reviewInfos().getContent().get(0).authorProfileImageUrl()).isEqualTo("naver.com"); + assertThat(result.reviewInfos().getContent().get(0).rating()).isEqualTo(20.5); + assertThat(result.reviewInfos().getContent().get(0).isAuthor()).isEqualTo(true); + assertThat(result.reviewTotalCount()).isEqualTo(10); + } + + @Test + @DisplayName("리뷰를 작성 할 수 있다.") + public void createReviewSuccess() { + + given(memberRepository.findById(any())).willReturn(Optional.of(newBasicMember())); + given(tourItemRepository.findById(any())).willReturn(Optional.of(tourItem())); + given(reviewRepository.save(any())).willReturn(review()); + given(keywordRepository.findById(any())).willReturn(Optional.of(keyword())); + + ReviewInfo result = reviewService.createReview(newBasicMember().getId(), reviewCreateRequest()); + + assertNotNull(result); + assertThat(result.authorNickname()).isEqualTo("nickNameTest"); + assertThat(result.content()).isEqualTo("review content test"); + assertThat(result.authorProfileImageUrl()).isEqualTo("naver.com"); + assertThat(result.rating()).isEqualTo(2.5); + assertThat(result.isAuthor()).isEqualTo(true); + } + + @Test + @DisplayName("리뷰를 업데이트 할 수 있다.") + public void updateReviewSuccess() { + + + given(memberRepository.findById(any())).willReturn(Optional.of(newBasicMember())); + given(reviewRepository.findById(any())).willReturn(Optional.of(review())); + given(keywordRepository.findById(any())).willReturn(Optional.of(keyword())); + assertDoesNotThrow(()->reviewKeywordRepository.deleteByReviewId(any())); + given(reviewKeywordRepository.saveAll(any())).willReturn(List.of(reviewKeyword())); + + ReviewInfo result = reviewService.updateReview(newBasicMember().getId(), review().getId(), reviewUpdateRequest()); + + // Assertions + assertNotNull(result); + assertThat(result.authorNickname()).isEqualTo("nickNameTest"); + assertThat(result.content()).isEqualTo("Review Update Content"); + assertThat(result.authorProfileImageUrl()).isEqualTo("naver.com"); + assertThat(result.rating()).isEqualTo(42.3); + assertThat(result.isAuthor()).isEqualTo(true); + } + + @Test + @DisplayName("리뷰를 삭제할 수 있다.") + public void deleteReviewSuccess() { + + Review review = review(); + + given(memberRepository.findById(any())).willReturn((Optional.of(review.getCreator()))); + given(reviewRepository.findById(any())).willReturn((Optional.of(review))); + + assertDoesNotThrow(() -> reviewService.deleteReview(review().getCreator().getId(), review.getId())); + + } + + @Test + @DisplayName("리뷰에서 댓글 조회를 할 수 있다.") + public void getReviewComment(){ + + Comment savedComment = saveComment(commentCreateRequest().content(), review(), newBasicMember()); + Pageable pageable = PageRequest.of(0, 10); + given(commentRepository.findCommentsByReviewId(any(),any())).willReturn(new PageImpl<>(List.of(savedComment), pageable, 10)); + + CommentResponse result = reviewService.getReviewComments(review().getId(), pageable, newBasicMember().getId()); + + assertNotNull(result); + assertThat(result.comments().getContent().get(0).authorNickname()).isEqualTo("nickNameTest"); + assertThat(result.comments().getContent().get(0).content()).isEqualTo("success create comment"); + assertThat(result.comments().getContent().get(0).authorProfileImageUrl()).isEqualTo("naver.com"); + } + + @Test + @DisplayName("리뷰에서 키워드를 조회할 수 있다.") + public void getKeyWords(){ + + KeywordResponse keywordResponse = keywordResponse(); + given(keywordRepository.findAll()).willReturn(List.of(keyword())); + KeywordResponse result = reviewService.getKeywords(null); + assertThat(result.keywords()).isEqualTo(keywordResponse.keywords()); + } +} diff --git a/src/test/java/org/tenten/tentenbe/domain/tour/controller/TourControllerTest.java b/src/test/java/org/tenten/tentenbe/domain/tour/controller/TourControllerTest.java new file mode 100644 index 00000000..73d3b152 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/tour/controller/TourControllerTest.java @@ -0,0 +1,90 @@ +package org.tenten.tentenbe.domain.tour.controller; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.tenten.tentenbe.common.ControllerTest; +import org.tenten.tentenbe.domain.review.service.ReviewService; +import org.tenten.tentenbe.domain.tour.dto.response.TourDetailResponse; +import org.tenten.tentenbe.domain.tour.service.TourService; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +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 static org.tenten.tentenbe.common.fixture.MemberFixture.tourItem; +import static org.tenten.tentenbe.common.fixture.ReviewFixture.reviewResponse; +import static org.tenten.tentenbe.common.fixture.TourFixture.tourSimpleResponsePage; + +public class TourControllerTest extends ControllerTest { + + @MockBean + private TourService tourService; + @MockBean + private ReviewService reviewService; + @Test + @DisplayName("인기 여행지 조회 성공") + public void searchFamousTourSuccess() throws Exception { + + given(tourService.getTours(any(), any(), any())).willReturn(tourSimpleResponsePage()); + + mockMvc.perform(get("/api/tours")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.content.[0].title").value("test title")) + .andExpect(jsonPath("$.data.content.[0].tourAddress").value("test address")) + .andExpect(jsonPath("$.data.content.[0].longitude").value("longitude")) + .andExpect(jsonPath("$.data.content.[0].reviewCount").value(10L)) + .andExpect(jsonPath("$.data.content.[0].likedCount").value(20L)) + .andDo(print()); + } + + @Test + @DisplayName("여행지 검색 성공") + public void searchTourSuccess() throws Exception { + given(tourService.searchTours(any(), any(), any(),any(),any())).willReturn(tourSimpleResponsePage()); + + mockMvc.perform(get("/api/tours/search?searchWord=test")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.content.[0].title").value("test title")) + .andExpect(jsonPath("$.data.content.[0].tourAddress").value("test address")) + .andExpect(jsonPath("$.data.content.[0].longitude").value("longitude")) + .andExpect(jsonPath("$.data.content.[0].reviewCount").value(10L)) + .andExpect(jsonPath("$.data.content.[0].likedCount").value(20L)) + .andDo(print()); + } + @Test + @DisplayName("여행지 상세 조회 성공") + public void searchSpecificTourSuccess() throws Exception { + TourDetailResponse tourSimpleResponse = new TourDetailResponse(tourItem(), true, "full address"); + + given(tourService.getTourDetail(any(), any())).willReturn(tourSimpleResponse); + + mockMvc.perform(get("/api/tours/10")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.title").value("test title")) + .andExpect(jsonPath("$.data.fullAddress").value("full address")) + .andExpect(jsonPath("$.data.longitude").value("longitude")) + .andExpect(jsonPath("$.data.tel").value("test telephone")) + .andExpect(jsonPath("$.data.liked").value(true)) + .andDo(print()); + } + + @Test + @DisplayName("여행 상품 리뷰 조회 성공") + public void reviewTourSuccess() throws Exception { + + given(reviewService.getTourReviews(any(), any(),any())).willReturn(reviewResponse()); + + mockMvc.perform(get("/api/tours/10/reviews")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.ratingAverage").value(20.2)) + .andExpect(jsonPath("$.data.reviewTotalCount").value(10L)) + .andExpect(jsonPath("$.data.keywordTotalCount").value(15L)) + .andExpect(jsonPath("$.data.reviewInfos.content.[0].authorNickname").value("nickNameTest")) + .andExpect(jsonPath("$.data.reviewInfos.content.[0].content").value("hello world")) + .andDo(print()); + } + +} diff --git a/src/test/java/org/tenten/tentenbe/domain/tour/repository/TourRepositoryTest.java b/src/test/java/org/tenten/tentenbe/domain/tour/repository/TourRepositoryTest.java new file mode 100644 index 00000000..d100a088 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/tour/repository/TourRepositoryTest.java @@ -0,0 +1,112 @@ +package org.tenten.tentenbe.domain.tour.repository; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.tenten.tentenbe.common.RepositoryTest; +import org.tenten.tentenbe.domain.liked.model.LikedItem; +import org.tenten.tentenbe.domain.member.model.Member; +import org.tenten.tentenbe.domain.tour.dto.response.TourSimpleResponse; +import org.tenten.tentenbe.domain.tour.model.TourItem; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.tenten.tentenbe.common.fixture.AuthFixture.newBasicMember; +import static org.tenten.tentenbe.common.fixture.AuthFixture.updateMember; +import static org.tenten.tentenbe.common.fixture.MemberFixture.*; + +public class TourRepositoryTest extends RepositoryTest { + + @Test + @DisplayName("회원 조회가 가능하다") + public void findMemberSuccess() throws Exception { + Member savedMember = memberRepository.save(newBasicMember()); + Optional findMember = memberRepository.findById(savedMember.getId()); + + assertThat(savedMember.getId()).isEqualTo(findMember.get().getId()); + } + + @Nested + @DisplayName("tourItemsRepository 에서") + class tourItemRepository { + @Test + @DisplayName("인기 여행 아이템 조회가 가능하다. ") + public void findById() throws Exception { + + Pageable pageable = PageRequest.of(0, 10); + + tourItemRepository.save(tourItem()); + Page findPopularTourItem = tourItemRepository.findPopularTourItems(newBasicMember().getId(), pageable); + + assertThat(findPopularTourItem.getContent().get(0).likedCount()).isEqualTo(20L); + assertThat(findPopularTourItem.getContent().get(0).tourAddress()).isEqualTo("test address"); + assertThat(findPopularTourItem.getContent().get(0).reviewCount()).isEqualTo(10L); + assertThat(findPopularTourItem.getContent().get(0).smallThumbnailUrl()).isEqualTo("small thumnail url"); + + } + + @Test + @DisplayName("지역 카테고리 필터 조회가 가능하다.") + public void findPopularTourItems() throws Exception { + + Pageable pageable = PageRequest.of(0, 10); + + Long regionCode = 1L; + Long categoryCode = 12L; + String searchWord = "search address"; + + tourItemRepository.saveAll(List.of(tourItem(),tourItemSecond())); + + Page searchTourItem = tourItemRepository.searchByRegionAndCategoryAndSearchWord(regionCode, categoryCode, searchWord, pageable); + + assertThat(searchTourItem.getContent().size()).isEqualTo(1); + assertThat(searchTourItem.getContent().get(0).getContentId()).isEqualTo(1L); + assertThat(searchTourItem.getContent().get(0).getContentTypeId()).isEqualTo(12L); + assertThat(searchTourItem.getContent().get(0).getAreaCode()).isEqualTo(1L); + assertThat(searchTourItem.getContent().get(0).getAddress()).isEqualTo("search address"); + } + } + + @Nested + @DisplayName("likedItemRepository 에서") + class likedItemRepository { + @Test + @DisplayName("해당 유저가 여행 상품에 좋아요를 '누른지' 확인 가능하다.") + public void existsTourItemSuccess() throws Exception { + + Member savedMember = memberRepository.save(newBasicMember()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + + LikedItem likedItem = likedSaveItem(savedMember,savedTourItem); + likedItemRepository.save(likedItem); + + Boolean result = likedItemRepository.existsByMemberIdAndTourItemId(savedMember.getId(), savedTourItem.getId()); + + assertThat(result).isEqualTo(true); + + } + + @Test + @DisplayName("해당 유저가 여행 상품에 좋아요를 누르지 '않은지' 확인 가능하다.") + public void existsTourItemFail() throws Exception { + + Member savedMember = memberRepository.save(newBasicMember()); + Member savedOtherMember = memberRepository.save(updateMember()); + + TourItem savedTourItem = tourItemRepository.save(tourItem()); + + LikedItem likedItem = likedSaveItem(savedMember,savedTourItem); + likedItemRepository.save(likedItem); + + Boolean result = likedItemRepository.existsByMemberIdAndTourItemId(savedOtherMember.getId(), savedTourItem.getId()); + + assertThat(result).isEqualTo(false); + + } + } +} diff --git a/src/test/java/org/tenten/tentenbe/domain/tour/service/TourServiceTest.java b/src/test/java/org/tenten/tentenbe/domain/tour/service/TourServiceTest.java new file mode 100644 index 00000000..235f859b --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/tour/service/TourServiceTest.java @@ -0,0 +1,102 @@ +package org.tenten.tentenbe.domain.tour.service; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.tenten.tentenbe.common.ServiceTest; +import org.tenten.tentenbe.domain.liked.repository.LikedItemRepository; +import org.tenten.tentenbe.domain.member.repository.MemberRepository; +import org.tenten.tentenbe.domain.tour.dto.response.TourDetailResponse; +import org.tenten.tentenbe.domain.tour.dto.response.TourSimpleResponse; +import org.tenten.tentenbe.domain.tour.repository.TourItemRepository; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.tenten.tentenbe.common.fixture.AuthFixture.newBasicMember; +import static org.tenten.tentenbe.common.fixture.MemberFixture.tourItem; +import static org.tenten.tentenbe.common.fixture.TourFixture.tourSimpleResponsePage; + +public class TourServiceTest extends ServiceTest { + + @InjectMocks + private TourService tourService; + @Mock + private TourItemRepository tourItemRepository; + @Mock + private MemberRepository memberRepository; + @Mock + private LikedItemRepository likedItemRepository; + + @Test + @DisplayName("인기 여행지 조회시 페이지 리스트 값이 반환된다.") + public void getToursSuccess(){ + + Pageable pageable = PageRequest.of(0, 10); + + given(memberRepository.getReferenceById(any())).willReturn(newBasicMember()); + given(tourItemRepository.findPopularTourItems(any(), any())).willReturn(tourSimpleResponsePage()); + + Page result = tourService.getTours(newBasicMember().getId(),any(), pageable); + + assertNotNull(result); + + assertThat(result.getContent().get(0).title()).isEqualTo("test title"); + assertThat(result.getContent().get(0).tourAddress()).isEqualTo("test address"); + assertThat(result.getContent().get(0).longitude()).isEqualTo("longitude"); + assertThat(result.getContent().get(0).reviewCount()).isEqualTo(10L); + assertThat(result.getContent().get(0).likedCount()).isEqualTo(20L); + } + + @Test + @DisplayName("지역 여행 조회시 페이지 리스트 값이 반환된다.") + public void searchToursSuccess(){ + + Pageable pageable = PageRequest.of(0, 10); + + given(memberRepository.getReferenceById(any())).willReturn(newBasicMember()); + given(tourItemRepository.searchByRegionAndCategoryAndSearchWord(any(), any(),any(),any())) + .willReturn(new PageImpl<>(List.of(tourItem()))); + + Page result = tourService.searchTours(newBasicMember().getId(),"서울","관광지",any(), pageable); + + assertNotNull(result); + + assertThat(result.getContent().get(0).title()).isEqualTo("test title"); + assertThat(result.getContent().get(0).tourAddress()).isEqualTo("test address"); + assertThat(result.getContent().get(0).longitude()).isEqualTo("longitude"); + assertThat(result.getContent().get(0).reviewCount()).isEqualTo(10L); + assertThat(result.getContent().get(0).likedCount()).isEqualTo(20L); + + } + + @Test + @DisplayName("여행 상세 조회시 TourDetail 값이 반환된다.") + public void searchDetailToursSuccess(){ + + Pageable pageable = PageRequest.of(0, 10); + + given(memberRepository.getReferenceById(any())).willReturn(newBasicMember()); + given(tourItemRepository.findById(any())).willReturn(Optional.ofNullable(tourItem())); + given(likedItemRepository.existsByMemberIdAndTourItemId(any(), any())).willReturn(true); + + TourDetailResponse result = tourService.getTourDetail(newBasicMember().getId(),1L); + + assertNotNull(result); + + assertThat(result).extracting( + "title", "fullAddress", "longitude", "tel", "liked" + ).containsExactly("test title", "test address test detail address", "longitude", "test telephone", true); + + } + +} diff --git a/src/test/java/org/tenten/tentenbe/domain/trip/controller/TripControllerTest.java b/src/test/java/org/tenten/tentenbe/domain/trip/controller/TripControllerTest.java new file mode 100644 index 00000000..8bc3b72c --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/trip/controller/TripControllerTest.java @@ -0,0 +1,165 @@ +package org.tenten.tentenbe.domain.trip.controller; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.http.MediaType; +import org.tenten.tentenbe.common.ControllerTest; +import org.tenten.tentenbe.config.WithMockCustomUser; +import org.tenten.tentenbe.domain.trip.dto.response.TripCreateResponse; +import org.tenten.tentenbe.domain.trip.dto.response.TripLikedSimpleResponse; +import org.tenten.tentenbe.domain.trip.dto.response.TripSimpleResponse; +import org.tenten.tentenbe.domain.trip.service.TripService; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +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; +import static org.tenten.tentenbe.common.fixture.TripFixture.*; + +public class TripControllerTest extends ControllerTest { + + @MockBean + private TripService tripService; + + @Test + @DisplayName("여정 생성 성공") + public void createTripSuccess() throws Exception { + + given(tripService.createTrip(any(), any())).willReturn(new TripCreateResponse(1L)); + + mockMvc.perform(post("/api/trips") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(tripCreateRequest()))) + .andExpect(jsonPath("$.data.tripId").value(1L)) + .andDo(print()); + } + + @Test + @DisplayName("나의 여정목록 조회 성공") + public void getTripsSuccess() throws Exception { + + Pageable pageable = PageRequest.of(0, 10); + + List tripSimpleResponseList = List.of(tripSimpleResponse()); + Page tripSimpleResponsePage = new PageImpl<>(tripSimpleResponseList, pageable, tripSimpleResponseList.size()); + + given(tripService.getTrips(any(), any())).willReturn(tripSimpleResponsePage); + + mockMvc.perform(get("/api/trips")) + .andExpect(jsonPath("$.data.content.[0].tripId").value(1L)) + .andExpect(jsonPath("$.data.content.[0].tripName").value("my first trip response")) + .andExpect(jsonPath("$.data.content.[0].numberOfTripMembers").value(4L)) + .andDo(print()); + } + + @Test + @DisplayName("여정 상세조회 성공") + public void getDetailTripSuccess() throws Exception { + + given(tripService.getTrip(any())).willReturn(tripDetailResponse()); + + mockMvc.perform(get("/api/trips/1")) + .andExpect(jsonPath("$.data.tripName").value("trip name test")) + .andExpect(jsonPath("$.data.startDate").value("2024-01-01")) + .andExpect(jsonPath("$.data.endDate").value("2024-01-06")) + .andDo(print()); + } + + @Test + @DisplayName("여정 정보 수정 성공") + public void updateTripSuccess() throws Exception { + given(tripService.updateTrip(any(), any(), any())).willReturn(tripInfoUpdateResponse()); + + mockMvc.perform(put("/api/trips/1") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(tripInfoUpdateRequest()))) + .andExpect(jsonPath("$.data.tripName").value("my second trip response")) + .andExpect(jsonPath("$.data.startDate").value("2024-01-01")) + .andExpect(jsonPath("$.data.endDate").value("2024-01-06")) + .andExpect(jsonPath("$.data.area").value("서울시")) + .andExpect(jsonPath("$.data.subarea").value("강남구")) + .andDo(print()); + + } + + @Test + @DisplayName("여정 탈퇴 성공") + public void deleteTripMemberSuccess() throws Exception { + + //TODO:: 코드 완성 + mockMvc.perform(delete("/api/trips/1")) + .andExpect(status().isOk()) + .andDo(print()); + + } + + @Test + @DisplayName("그룹 관심 여행지 등록 성공") + public void LikeTourInOurTripSuccess() throws Exception { + + mockMvc.perform(post("/api/trips/1/tripLikedTours") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsBytes(tripLikedItemRequest()))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").value("SUCCESS")) + .andDo(print()); + + } + + @Test + @WithMockCustomUser + @DisplayName("그룹 관심목록 조회 성공") + public void getTripLikedItemsSuccess() throws Exception { + + Pageable pageable = PageRequest.of(0, 10); + + List tripLikedSimpleResponses = List.of(tripLikedSimpleResponse()); + Page tripSimpleResponsePage = new PageImpl<>(tripLikedSimpleResponses, pageable, tripLikedSimpleResponses.size()); + + given(tripService.getTripLikedItems(any(), any(), any(), any())).willReturn(tripSimpleResponsePage); + + mockMvc.perform(get("/api/trips/1/tripLikedTours")) + .andExpect(jsonPath("$.data.content.[0].tripLikedItemId").value(1L)) + .andExpect(jsonPath("$.data.content.[0].ratingAverage").value(2.5)) + .andExpect(jsonPath("$.data.content.[0].reviewCount").value(10L)) + .andExpect(jsonPath("$.data.content.[0].notPreferTotalCount").value(3L)) + .andDo(print()); + } + + @Test + @DisplayName("그룹 관심 여행지 좋아요 여부 확인 성공") + public void preferOrNotTourInOurTripSuccess() throws Exception { + + mockMvc.perform(post("/api/trips/1/tripLikedTours/1?prefer=true¬Prefer=true")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").value("SUCCESS")) + .andDo(print()); + } + + @Test + @DisplayName("그룹 여행 취향 조회") + public void getTripSurveysSuccess() throws Exception { + + given(tripService.getTripSurveys(any())).willReturn(tripSurveyResponse()); + + mockMvc.perform(get("/api/trips/1/survey")) + .andExpect(jsonPath("$.data.planningTotalCount").value(20L)) + .andExpect(jsonPath("$.data.planningCount").value(10L)) + .andExpect(jsonPath("$.data.activeHoursTotalCount").value(30L)) + .andExpect(jsonPath("$.data.activeHoursCount").value(40L)) + .andExpect(jsonPath("$.data.accommodationTotalCount").value(4L)) + .andExpect(jsonPath("$.data.accommodationCount").value(2L)) + .andDo(print()); + + } + +} diff --git a/src/test/java/org/tenten/tentenbe/domain/trip/repository/TripRepositoryTest.java b/src/test/java/org/tenten/tentenbe/domain/trip/repository/TripRepositoryTest.java new file mode 100644 index 00000000..c11216b9 --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/trip/repository/TripRepositoryTest.java @@ -0,0 +1,149 @@ +package org.tenten.tentenbe.domain.trip.repository; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.tenten.tentenbe.common.RepositoryTest; +import org.tenten.tentenbe.domain.member.model.Member; +import org.tenten.tentenbe.domain.tour.model.TourItem; +import org.tenten.tentenbe.domain.trip.dto.response.TripLikedSimpleResponse; +import org.tenten.tentenbe.domain.trip.dto.response.TripSimpleResponse; +import org.tenten.tentenbe.domain.trip.model.Trip; +import org.tenten.tentenbe.domain.trip.model.TripLikedItem; +import org.tenten.tentenbe.domain.trip.model.TripLikedItemPreference; +import org.tenten.tentenbe.domain.trip.model.TripMember; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.tenten.tentenbe.common.fixture.AuthFixture.newBasicMember; +import static org.tenten.tentenbe.common.fixture.MemberFixture.tourItem; +import static org.tenten.tentenbe.common.fixture.TripFixture.*; + + +public class TripRepositoryTest extends RepositoryTest { + + @Test + @DisplayName("여정 저장이 가능하다.") + public void canSaveTripMemberRepository() throws Exception { + Member savedmember = memberRepository.save(newBasicMember()); + Trip savedTrip = tripRepository.save(trip()); + + List result = tripMemberRepository.saveAll(List.of(savedTripMember(savedmember,savedTrip),savedTripMember(savedmember,savedTrip))); + + assertThat(result.size()).isEqualTo(2); + } + @Test + @DisplayName("회원의 총 여정 횟수 조회가 가능하다.") + public void countTripMemberByMemberSuccess() throws Exception { + Member savedmember = memberRepository.save(newBasicMember()); + Trip savedTrip = tripRepository.save(trip()); + tripMemberRepository.saveAll(List.of(savedTripMember(savedmember,savedTrip),savedTripMember(savedmember,savedTrip))); + + Long numberOfTrip = tripMemberRepository.countTripMemberByMember(savedmember); + + assertThat(numberOfTrip).isEqualTo(2); + } + + @Test + @DisplayName("나의 여정 목록 조회가 가능하다.") + public void myTripCanSearch() throws Exception { + + Pageable pageable = PageRequest.of(0, 10); + + Member savedmember = memberRepository.save(newBasicMember()); + Trip savedTrip = tripRepository.save(trip()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + + tripItemRepository.save(savetripItem(savedTrip,savedTourItem)); + tripMemberRepository.save(savedTripMember(savedmember,savedTrip)); + + Page result = tripRepository.findTripsByMemberId(savedmember.getId(),pageable); + + assertThat(result.getContent().get(0).tripName()).isEqualTo("test trip name"); + } + + @Test + @DisplayName("여정 상세 조회가 가능하다.") + public void tripDetailSearch() throws Exception { + Trip savedTrip = tripRepository.save(trip()); + + Optional result = tripRepository.findById(savedTrip.getId()); + + assertThat(result.get().getTripName()).isEqualTo(trip().getTripName()); + assertThat(result.get().getStartDate()).isEqualTo(trip().getStartDate()); + + assertThat(result.get()).isEqualTo(savedTrip); + } + + @Test + @DisplayName("여정 업데이트가 가능하다.") + public void tripUpdate() throws Exception { + Trip savedTrip = tripRepository.save(trip()); + + savedTrip.updateTripInfo(tripInfoUpdateRequest()); + + Trip savedUpdateTrip = tripRepository.save(savedTrip); + + assertThat(savedTrip.getTripName()).isEqualTo(savedUpdateTrip.getTripName()); + assertThat(savedTrip.getStartDate()).isEqualTo(savedUpdateTrip.getStartDate()); + + assertThat(savedTrip).isEqualTo(savedUpdateTrip); + + } + @Test + @DisplayName("그룹 관심 여행지 등록이 가능하다.") + public void likeTourInOutTrip() throws Exception { + + Trip savedTrip = tripRepository.save(trip()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + TripLikedItem savedTripLikedItem = tripLikedItemRepository.save(saveTripLikedItem(savedTrip,savedTourItem)); + + assertThat(savedTripLikedItem.getTrip()).usingRecursiveComparison().isEqualTo(savedTrip); + assertThat(savedTripLikedItem.getTourItem()).usingRecursiveComparison().isEqualTo(tourItem()); + + } + + + @Test + @DisplayName("그룹 관심 목록 조회가 가능하다.") + public void getTripLikedItems() throws Exception { + + Pageable pageable = PageRequest.of(0, 10); + Member savedMember = memberRepository.save(newBasicMember()); + Trip savedTrip = tripRepository.save(trip()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + TripLikedItem savedTripLikedItem = tripLikedItemRepository.save(saveTripLikedItem(savedTrip,savedTourItem)); + + Page result = tripLikedItemRepository + .findTripLikedItemsById(savedMember.getId(), savedTrip.getId(), 12L, pageable); + + + //TODO:: 관심 그룹 목록 조회가 완료후 재 테스트 + + assertThat(savedTripLikedItem).isEqualTo(result.getContent().get(0)); + + } + + @Test + @DisplayName("그룹 관심 여행지 좋아요 /싫어요 저장 가능하다. ") + public void preferOrNotTourInOurTrip() throws Exception { + + Member savedMember = memberRepository.save(newBasicMember()); + Trip savedTrip = tripRepository.save(trip()); + TourItem savedTourItem = tourItemRepository.save(tourItem()); + TripMember savedTripMember = tripMemberRepository.save(savedTripMember(savedMember, savedTrip)); + + TripLikedItem savedTripLikedItem = tripLikedItemRepository.save(saveTripLikedItem(savedTrip,savedTourItem)); + + TripLikedItemPreference savedTripLikedItemPreference = + tripLikedItemPreferenceRepository.save(saveTripLikedItemPreference(savedTripMember, savedTripLikedItem)); + + Optional result = tripLikedItemPreferenceRepository.findById(savedTripLikedItemPreference.getId()); + + assertThat(result.get()).usingRecursiveComparison().isEqualTo(savedTripLikedItemPreference); + } +} diff --git a/src/test/java/org/tenten/tentenbe/domain/trip/service/TripServiceTest.java b/src/test/java/org/tenten/tentenbe/domain/trip/service/TripServiceTest.java new file mode 100644 index 00000000..e6c3b08d --- /dev/null +++ b/src/test/java/org/tenten/tentenbe/domain/trip/service/TripServiceTest.java @@ -0,0 +1,189 @@ +package org.tenten.tentenbe.domain.trip.service; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.tenten.tentenbe.common.ServiceTest; +import org.tenten.tentenbe.domain.member.repository.MemberRepository; +import org.tenten.tentenbe.domain.tour.repository.TourItemRepository; +import org.tenten.tentenbe.domain.trip.dto.response.*; +import org.tenten.tentenbe.domain.trip.model.TripLikedItem; +import org.tenten.tentenbe.domain.trip.model.TripLikedItemPreference; +import org.tenten.tentenbe.domain.trip.repository.TripLikedItemPreferenceRepository; +import org.tenten.tentenbe.domain.trip.repository.TripLikedItemRepository; +import org.tenten.tentenbe.domain.trip.repository.TripMemberRepository; +import org.tenten.tentenbe.domain.trip.repository.TripRepository; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.tenten.tentenbe.common.fixture.AuthFixture.newBasicMember; +import static org.tenten.tentenbe.common.fixture.MemberFixture.tourItem; +import static org.tenten.tentenbe.common.fixture.TripFixture.*; + +public class TripServiceTest extends ServiceTest { + + @InjectMocks + private TripService tripService; + @Mock + private TripRepository tripRepository; + @Mock + private TourItemRepository tourItemRepository; + @Mock + private MemberRepository memberRepository; + @Mock + private TripMemberRepository tripMemberRepository; + @Mock + private TripLikedItemRepository tripLikedItemRepository; + @Mock + private TripLikedItemPreferenceRepository tripLikedItemPreferenceRepository; + + @Test + @DisplayName("여정 생성이 가능하다.") + public void createTripSuccess(){ + + given(tripMemberRepository.countTripMemberByMember(any())).willReturn(1L); + given(tripMemberRepository.save(any())).willReturn(savedTripMember(newBasicMember(),trip())); + given(tripRepository.save(any())).willReturn(trip()); + + TripCreateResponse result = tripService.createTrip(newBasicMember().getId(), tripCreateRequest()); + + assertNotNull(result); + assertThat(result.tripId()).isEqualTo(10L); + } + + @Test + @DisplayName("여정 조회가 가능하다.") + public void getTripsSuccess(){ + + Pageable pageable = PageRequest.of(0, 10); + + List tripSimpleResponseList = List.of(tripSimpleResponse()); + Page tripSimpleResponsePage = new PageImpl<>(tripSimpleResponseList, pageable, tripSimpleResponseList.size()); + + given(tripRepository.findTripsByMemberId(any(),any())).willReturn(tripSimpleResponsePage); + + Page result = tripService.getTrips(newBasicMember().getId(), pageable); + + assertNotNull(result); + + assertThat(result.getContent()).usingRecursiveAssertion().isEqualTo(tripSimpleResponsePage.getContent()); + } + + @Test + @DisplayName("상세 여정 조회가 가능하다.") + public void getTripSuccess(){ + + given(tripRepository.findById(any())).willReturn(Optional.ofNullable(trip())); + + TripDetailResponse result = tripService.getTrip(trip().getId()); + + assertNotNull(result); + assertThat(result.tripName()).isEqualTo(trip().getTripName()); + assertThat(result.startDate()).isEqualTo(trip().getStartDate()); + assertThat(result.endDate()).isEqualTo(trip().getEndDate()); + } + + @Test + @DisplayName("여정 업데이트가 가능하다.") + public void updateTripSuccess(){ + + given(memberRepository.getReferenceById(any())).willReturn(newBasicMember()); + given(tripRepository.findById(any())).willReturn(Optional.ofNullable(trip())); + given(tripRepository.save(any())).willReturn(trip()); + + TripInfoUpdateResponse result = tripService.updateTrip(newBasicMember().getId(), trip().getId(),tripInfoUpdateRequest()); + + assertNotNull(result); + assertThat(result.tripName()).isEqualTo(tripInfoUpdateRequest().tripName()); + } + + @Test + @DisplayName("여정 멤버 삭제가 가능하다.") + public void deleteTripMemberSuccess(){ + //TODO:: 구현 구상 후 작성 예정 + } + + @Test + @DisplayName("그룹 관심 여행지 등록 이 가능하다.") + public void LikeTourInOurTripSuccess(){ + + given(memberRepository.getReferenceById(any())).willReturn(newBasicMember()); + given(tripRepository.findById(any())).willReturn(Optional.ofNullable(trip())); + given(tourItemRepository.findById(any())).willReturn(Optional.ofNullable(tourItem())); + given(tripLikedItemRepository.findByTripAndTourItem(any(),any())) + .willReturn(Optional.empty()); + + tripService.LikeTourInOurTrip(newBasicMember().getId(), trip().getId(), tripLikedItemRequest()); + + verify(tripLikedItemRepository, times(4)).save(any(TripLikedItem.class)); + + } + + @Test + @DisplayName("그룹 관심 목록 조회가 가능하다. ") + public void getTripLikedItemsSuccess(){ + + Pageable pageable = PageRequest.of(0, 10); + + List tripLikedItems = List.of(saveTripLikedItem(trip(),tourItem())); + Page tripLikedItemPage = new PageImpl<>(tripLikedItems, pageable, tripLikedItems.size()); + + + given(memberRepository.getReferenceById(any())).willReturn(newBasicMember()); + given(tripRepository.findById(any())).willReturn(Optional.ofNullable(trip())); + given(tripLikedItemRepository.findTripLikedItemsById(any(), any(), any(), any())) + .willReturn(new PageImpl<>(List.of(tripLikedSimpleResponse()), pageable, tripLikedItems.size())); + + Page result = tripService.getTripLikedItems(newBasicMember().getId(), trip().getId(), "관광지", pageable); + + assertNotNull(result); + + assertThat(result.getContent()).usingRecursiveComparison() + .isEqualTo(List.of(tripLikedSimpleResponse())); + + } + + @Test + @DisplayName("그룹 관심 여행지 좋아요 여부 확인 이 가능하다.") + public void preferOrNotTourInOurTripSuccess(){ + + given(tripRepository.findById(any())).willReturn(Optional.ofNullable(trip())); + given(tourItemRepository.findById(any())).willReturn(Optional.ofNullable(tourItem())); + given(tripMemberRepository.findByMemberAndTrip(any(),any())).willReturn(Optional.ofNullable(savedTripMember(newBasicMember(),trip()))); + given(tripLikedItemRepository.findByTripAndTourItem(any(), any())) + .willReturn(Optional.ofNullable(saveTripLikedItem(trip(), tourItem()))); +// given(tripLikedItemPreferenceRepository.findByTripMemberAndTripLikedItem(savedTripMember(), saveTripLikedItem(trip(), tourItem()))) +// .willReturn(Optional.ofNullable(tripLikedItemPreference())); + + tripService.preferOrNotTourInOurTrip(newBasicMember().getId(), trip().getId(), tourItem().getId(), false, true); + + verify(tripLikedItemPreferenceRepository).save(any(TripLikedItemPreference.class)); + + } + + @Test + @DisplayName("그룹 여행 취향 조회가 가능하다.") + public void getTripSurveysSuccess(){ + + //TODO:: 코드 보완필 + given(tripRepository.findById(any())).willReturn(Optional.ofNullable(trip())); +// given(tripMemberRepository.findByMemberAndTrip(any(),any())).willReturn(Optional.ofNullable(savedTripMember())); + + TripSurveyResponse result = tripService.getTripSurveys(trip().getId()); + + assertThat(result.planningTotalCount()).isEqualTo(0); + + } +}