diff --git a/src/test/java/com/example/solidconnection/siteuser/service/SiteUserServiceTest.java b/src/test/java/com/example/solidconnection/siteuser/service/SiteUserServiceTest.java new file mode 100644 index 000000000..8fdae031e --- /dev/null +++ b/src/test/java/com/example/solidconnection/siteuser/service/SiteUserServiceTest.java @@ -0,0 +1,309 @@ +package com.example.solidconnection.siteuser.service; + +import com.example.solidconnection.custom.exception.CustomException; +import com.example.solidconnection.s3.S3Service; +import com.example.solidconnection.s3.UploadedFileUrlResponse; +import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.siteuser.dto.MyPageResponse; +import com.example.solidconnection.siteuser.dto.MyPageUpdateResponse; +import com.example.solidconnection.siteuser.dto.NicknameUpdateRequest; +import com.example.solidconnection.siteuser.dto.NicknameUpdateResponse; +import com.example.solidconnection.siteuser.dto.ProfileImageUpdateResponse; +import com.example.solidconnection.siteuser.repository.LikedUniversityRepository; +import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import com.example.solidconnection.support.integration.BaseIntegrationTest; +import com.example.solidconnection.type.Gender; +import com.example.solidconnection.type.ImgType; +import com.example.solidconnection.type.PreparationStatus; +import com.example.solidconnection.type.Role; +import com.example.solidconnection.university.domain.LikedUniversity; +import com.example.solidconnection.university.dto.UniversityInfoForApplyPreviewResponse; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockMultipartFile; + +import java.time.LocalDateTime; +import java.util.List; + +import static com.example.solidconnection.custom.exception.ErrorCode.CAN_NOT_CHANGE_NICKNAME_YET; +import static com.example.solidconnection.custom.exception.ErrorCode.NICKNAME_ALREADY_EXISTED; +import static com.example.solidconnection.custom.exception.ErrorCode.PROFILE_IMAGE_NEEDED; +import static com.example.solidconnection.siteuser.service.SiteUserService.MIN_DAYS_BETWEEN_NICKNAME_CHANGES; +import static com.example.solidconnection.siteuser.service.SiteUserService.NICKNAME_LAST_CHANGE_DATE_FORMAT; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.BDDMockito.never; +import static org.mockito.BDDMockito.any; +import static org.mockito.BDDMockito.eq; + +@DisplayName("유저 서비스 테스트") +class SiteUserServiceTest extends BaseIntegrationTest { + + @Autowired + private SiteUserService siteUserService; + + @MockBean + private S3Service s3Service; + + @Autowired + private SiteUserRepository siteUserRepository; + + @Autowired + private LikedUniversityRepository likedUniversityRepository; + + @Test + void 마이페이지_정보를_조회한다() { + // given + SiteUser testUser = createSiteUser(); + int likedUniversityCount = createLikedUniversities(testUser); + + // when + MyPageResponse response = siteUserService.getMyPageInfo(testUser.getEmail()); + + // then + Assertions.assertAll( + () -> assertThat(response.nickname()).isEqualTo(testUser.getNickname()), + () -> assertThat(response.profileImageUrl()).isEqualTo(testUser.getProfileImageUrl()), + () -> assertThat(response.role()).isEqualTo(testUser.getRole()), + () -> assertThat(response.birth()).isEqualTo(testUser.getBirth()), + () -> assertThat(response.email()).isEqualTo(testUser.getEmail()), + () -> assertThat(response.likedPostCount()).isEqualTo(testUser.getPostLikeList().size()), + () -> assertThat(response.likedUniversityCount()).isEqualTo(likedUniversityCount) + ); + } + + @Test + void 내_정보를_수정하기_위한_마이페이지_정보를_조회한다() { + // given + SiteUser testUser = createSiteUser(); + + // when + MyPageUpdateResponse response = siteUserService.getMyPageInfoToUpdate(testUser.getEmail()); + + // then + Assertions.assertAll( + () -> assertThat(response.nickname()).isEqualTo(testUser.getNickname()), + () -> assertThat(response.profileImageUrl()).isEqualTo(testUser.getProfileImageUrl()) + ); + } + + @Test + void 관심_대학교_목록을_조회한다() { + // given + SiteUser testUser = createSiteUser(); + int likedUniversityCount = createLikedUniversities(testUser); + + // when + List response = siteUserService.getWishUniversity(testUser.getEmail()); + + // then + assertThat(response) + .hasSize(likedUniversityCount) + .usingRecursiveFieldByFieldElementComparatorIgnoringFields("id") + .containsAll(List.of( + UniversityInfoForApplyPreviewResponse.from(괌대학_A_지원_정보), + UniversityInfoForApplyPreviewResponse.from(메이지대학_지원_정보), + UniversityInfoForApplyPreviewResponse.from(코펜하겐IT대학_지원_정보) + )); + } + + @Nested + class 프로필_이미지_수정_테스트 { + + @Test + void 새로운_이미지로_성공적으로_업데이트한다() { + // given + SiteUser testUser = createSiteUser(); + String expectedUrl = "newProfileImageUrl"; + MockMultipartFile imageFile = createValidImageFile(); + given(s3Service.uploadFile(any(), eq(ImgType.PROFILE))) + .willReturn(new UploadedFileUrlResponse(expectedUrl)); + + // when + ProfileImageUpdateResponse response = siteUserService.updateProfileImage( + testUser.getEmail(), + imageFile + ); + + // then + assertThat(response.profileImageUrl()).isEqualTo(expectedUrl); + } + + @Test + void 프로필을_처음_수정하는_것이면_이전_이미지를_삭제하지_않는다() { + // given + SiteUser testUser = createSiteUser(); + MockMultipartFile imageFile = createValidImageFile(); + given(s3Service.uploadFile(any(), eq(ImgType.PROFILE))) + .willReturn(new UploadedFileUrlResponse("newProfileImageUrl")); + + // when + siteUserService.updateProfileImage(testUser.getEmail(), imageFile); + + // then + then(s3Service).should(never()).deleteExProfile(any()); + } + + @Test + void 프로필을_처음_수정하는_것이_아니라면_이전_이미지를_삭제한다() { + // given + SiteUser testUser = createSiteUserWithCustomProfile(); + MockMultipartFile imageFile = createValidImageFile(); + given(s3Service.uploadFile(any(), eq(ImgType.PROFILE))) + .willReturn(new UploadedFileUrlResponse("newProfileImageUrl")); + + // when + siteUserService.updateProfileImage(testUser.getEmail(), imageFile); + + // then + then(s3Service).should().deleteExProfile(testUser.getEmail()); + } + + @Test + void 빈_이미지_파일로_프로필을_수정하면_예외_응답을_반환한다() { + // given + SiteUser testUser = createSiteUser(); + MockMultipartFile emptyFile = createEmptyImageFile(); + + // when & then + assertThatCode(() -> siteUserService.updateProfileImage(testUser.getEmail(), emptyFile)) + .isInstanceOf(CustomException.class) + .hasMessage(PROFILE_IMAGE_NEEDED.getMessage()); + } + } + + @Nested + class 닉네임_수정_테스트 { + + @Test + void 닉네임을_성공적으로_수정한다() { + // given + SiteUser testUser = createSiteUser(); + String newNickname = "newNickname"; + NicknameUpdateRequest request = new NicknameUpdateRequest(newNickname); + + // when + NicknameUpdateResponse response = siteUserService.updateNickname( + testUser.getEmail(), + request + ); + + // then + SiteUser updatedUser = siteUserRepository.getByEmail(testUser.getEmail()); + assertThat(updatedUser.getNicknameModifiedAt()).isNotNull(); + assertThat(response.nickname()).isEqualTo(newNickname); + } + + @Test + void 중복된_닉네임으로_변경하면_예외_응답을_반환한다() { + // given + createDuplicatedSiteUser(); + SiteUser testUser = createSiteUser(); + NicknameUpdateRequest request = new NicknameUpdateRequest("duplicatedNickname"); + + // when & then + assertThatCode(() -> siteUserService.updateNickname(testUser.getEmail(), request)) + .isInstanceOf(CustomException.class) + .hasMessage(NICKNAME_ALREADY_EXISTED.getMessage()); + } + + @Test + void 최소_대기기간이_지나지_않은_상태에서_변경하면_예외_응답을_반환한다() { + // given + SiteUser testUser = createSiteUser(); + LocalDateTime modifiedAt = LocalDateTime.now().minusDays(MIN_DAYS_BETWEEN_NICKNAME_CHANGES - 1); + testUser.setNicknameModifiedAt(modifiedAt); + siteUserRepository.save(testUser); + + NicknameUpdateRequest request = new NicknameUpdateRequest("newNickname"); + + // when & then + assertThatCode(() -> + siteUserService.updateNickname(testUser.getEmail(), request)) + .isInstanceOf(CustomException.class) + .hasMessage(createExpectedErrorMessage(modifiedAt)); + } + } + + private SiteUser createSiteUser() { + SiteUser siteUser = new SiteUser( + "test@example.com", + "nickname", + "profileImageUrl", + "1999-01-01", + PreparationStatus.CONSIDERING, + Role.MENTEE, + Gender.MALE + ); + return siteUserRepository.save(siteUser); + } + + private SiteUser createSiteUserWithCustomProfile() { + SiteUser siteUser = new SiteUser( + "test@example.com", + "nickname", + "profile/profileImageUrl", + "1999-01-01", + PreparationStatus.CONSIDERING, + Role.MENTEE, + Gender.MALE + ); + return siteUserRepository.save(siteUser); + } + + private void createDuplicatedSiteUser() { + SiteUser siteUser = new SiteUser( + "duplicated@example.com", + "duplicatedNickname", + "profileImageUrl", + "1999-01-01", + PreparationStatus.CONSIDERING, + Role.MENTEE, + Gender.MALE + ); + siteUserRepository.save(siteUser); + } + + private int createLikedUniversities(SiteUser testUser) { + LikedUniversity likedUniversity1 = new LikedUniversity(null, 괌대학_A_지원_정보, testUser); + LikedUniversity likedUniversity2 = new LikedUniversity(null, 메이지대학_지원_정보, testUser); + LikedUniversity likedUniversity3 = new LikedUniversity(null, 코펜하겐IT대학_지원_정보, testUser); + + likedUniversityRepository.save(likedUniversity1); + likedUniversityRepository.save(likedUniversity2); + likedUniversityRepository.save(likedUniversity3); + return likedUniversityRepository.countBySiteUser_Email(testUser.getEmail()); + } + + private MockMultipartFile createValidImageFile() { + return new MockMultipartFile( + "image", + "test.jpg", + "image/jpeg", + "test image content".getBytes() + ); + } + + private MockMultipartFile createEmptyImageFile() { + return new MockMultipartFile( + "image", + "empty.jpg", + "image/jpeg", + new byte[0] + ); + } + + private String createExpectedErrorMessage(LocalDateTime modifiedAt) { + String formatLastModifiedAt = String.format( + "(마지막 수정 시간 : %s)", + NICKNAME_LAST_CHANGE_DATE_FORMAT.format(modifiedAt) + ); + return CAN_NOT_CHANGE_NICKNAME_YET.getMessage() + " : " + formatLastModifiedAt; + } +} diff --git a/src/test/java/com/example/solidconnection/university/service/UniversityDataSetUpIntegrationTest.java b/src/test/java/com/example/solidconnection/support/integration/BaseIntegrationTest.java similarity index 96% rename from src/test/java/com/example/solidconnection/university/service/UniversityDataSetUpIntegrationTest.java rename to src/test/java/com/example/solidconnection/support/integration/BaseIntegrationTest.java index 91518a09e..b1f7d9203 100644 --- a/src/test/java/com/example/solidconnection/university/service/UniversityDataSetUpIntegrationTest.java +++ b/src/test/java/com/example/solidconnection/support/integration/BaseIntegrationTest.java @@ -1,4 +1,4 @@ -package com.example.solidconnection.university.service; +package com.example.solidconnection.support.integration; import com.example.solidconnection.entity.Country; import com.example.solidconnection.entity.Region; @@ -13,21 +13,19 @@ import com.example.solidconnection.university.repository.LanguageRequirementRepository; import com.example.solidconnection.university.repository.UniversityInfoForApplyRepository; import com.example.solidconnection.university.repository.UniversityRepository; -import io.restassured.RestAssured; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.web.server.LocalServerPort; import java.util.HashSet; import static com.example.solidconnection.type.SemesterAvailableForDispatch.ONE_SEMESTER; import static com.example.solidconnection.type.TuitionFeeType.HOME_UNIVERSITY_PAYMENT; -@ExtendWith(DatabaseClearExtension.class) @TestContainerSpringBootTest -abstract class UniversityDataSetUpIntegrationTest { +@ExtendWith(DatabaseClearExtension.class) +public abstract class BaseIntegrationTest { public static Region 영미권; public static Region 유럽; @@ -59,12 +57,6 @@ abstract class UniversityDataSetUpIntegrationTest { public static UniversityInfoForApply 린츠_카톨릭대학_지원_정보; public static UniversityInfoForApply 메이지대학_지원_정보; - @Value("${university.term}") - public String term; - - @LocalServerPort - private int port; - @Autowired private RegionRepository regionRepository; @@ -80,20 +72,33 @@ abstract class UniversityDataSetUpIntegrationTest { @Autowired private LanguageRequirementRepository languageRequirementRepository; + @Value("${university.term}") + public String term; + @BeforeEach - public void setUpBasicData() { - RestAssured.port = port; + public void setUpBaseData() { + setUpRegions(); + setUpCountries(); + setUpUniversities(); + setUpUniversityInfos(); + setUpLanguageRequirements(); + } + private void setUpRegions() { 영미권 = regionRepository.save(new Region("AMERICAS", "영미권")); 유럽 = regionRepository.save(new Region("EUROPE", "유럽")); 아시아 = regionRepository.save(new Region("ASIA", "아시아")); + } + private void setUpCountries() { 미국 = countryRepository.save(new Country("US", "미국", 영미권)); 캐나다 = countryRepository.save(new Country("CA", "캐나다", 영미권)); 덴마크 = countryRepository.save(new Country("DK", "덴마크", 유럽)); 오스트리아 = countryRepository.save(new Country("AT", "오스트리아", 유럽)); 일본 = countryRepository.save(new Country("JP", "일본", 아시아)); + } + private void setUpUniversities() { 영미권_미국_괌대학 = universityRepository.save(new University( null, "괌대학", "University of Guam", "university_of_guam", "https://www.uog.edu/admissions/international-students", @@ -179,7 +184,9 @@ public void setUpBasicData() { "https://solid-connection.s3.ap-northeast-2.amazonaws.com/original/meiji_university/1.png", null, 일본, 아시아 )); + } + private void setUpUniversityInfos() { 괌대학_A_지원_정보 = universityInfoForApplyRepository.save(new UniversityInfoForApply( null, term, "괌대학(A형)", 1, HOME_UNIVERSITY_PAYMENT, ONE_SEMESTER, "1", "detailsForLanguage", "gpaRequirement", @@ -259,7 +266,9 @@ public void setUpBasicData() { "detailsForAccommodation", "detailsForEnglishCourse", "details", new HashSet<>(), 아시아_일본_메이지대학 )); + } + private void setUpLanguageRequirements() { saveLanguageTestRequirement(괌대학_A_지원_정보, LanguageTestType.TOEFL_IBT, "80"); saveLanguageTestRequirement(괌대학_A_지원_정보, LanguageTestType.TOEIC, "800"); saveLanguageTestRequirement(괌대학_B_지원_정보, LanguageTestType.TOEFL_IBT, "70"); @@ -275,7 +284,10 @@ public void setUpBasicData() { } private void saveLanguageTestRequirement( - UniversityInfoForApply universityInfoForApply, LanguageTestType testType, String minScore) { + UniversityInfoForApply universityInfoForApply, + LanguageTestType testType, + String minScore + ) { LanguageRequirement languageRequirement = new LanguageRequirement( null, testType, diff --git a/src/test/java/com/example/solidconnection/university/service/UniversityLikeServiceTest.java b/src/test/java/com/example/solidconnection/university/service/UniversityLikeServiceTest.java index 50adf6839..14371486c 100644 --- a/src/test/java/com/example/solidconnection/university/service/UniversityLikeServiceTest.java +++ b/src/test/java/com/example/solidconnection/university/service/UniversityLikeServiceTest.java @@ -4,6 +4,7 @@ import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.repository.LikedUniversityRepository; import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import com.example.solidconnection.support.integration.BaseIntegrationTest; import com.example.solidconnection.type.Gender; import com.example.solidconnection.type.PreparationStatus; import com.example.solidconnection.type.Role; @@ -22,7 +23,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode; @DisplayName("대학교 좋아요 서비스 테스트") -class UniversityLikeServiceTest extends UniversityDataSetUpIntegrationTest { +class UniversityLikeServiceTest extends BaseIntegrationTest { @Autowired private UniversityLikeService universityLikeService; @@ -65,7 +66,7 @@ class UniversityLikeServiceTest extends UniversityDataSetUpIntegrationTest { } @Test - void 존재하지_않는_대학_좋아요_시도하면_예외를_반환한다() { + void 존재하지_않는_대학_좋아요_시도하면_예외_응답을_반환한다() { // given SiteUser testUser = createSiteUser(); Long invalidUniversityId = 9999L; @@ -102,7 +103,7 @@ class UniversityLikeServiceTest extends UniversityDataSetUpIntegrationTest { } @Test - void 존재하지_않는_대학의_좋아요_여부_조회시_예외를_반환한다() { + void 존재하지_않는_대학의_좋아요_여부를_조회하면_예외_응답을_반환한다() { // given SiteUser testUser = createSiteUser(); Long invalidUniversityId = 9999L; diff --git a/src/test/java/com/example/solidconnection/university/service/UniversityQueryServiceTest.java b/src/test/java/com/example/solidconnection/university/service/UniversityQueryServiceTest.java index 54c235452..1cd0d755f 100644 --- a/src/test/java/com/example/solidconnection/university/service/UniversityQueryServiceTest.java +++ b/src/test/java/com/example/solidconnection/university/service/UniversityQueryServiceTest.java @@ -1,6 +1,7 @@ package com.example.solidconnection.university.service; import com.example.solidconnection.custom.exception.CustomException; +import com.example.solidconnection.support.integration.BaseIntegrationTest; import com.example.solidconnection.type.LanguageTestType; import com.example.solidconnection.university.dto.UniversityDetailResponse; import com.example.solidconnection.university.dto.LanguageRequirementResponse; @@ -23,7 +24,7 @@ import static org.mockito.Mockito.times; @DisplayName("대학교 조회 서비스 테스트") -class UniversityQueryServiceTest extends UniversityDataSetUpIntegrationTest { +class UniversityQueryServiceTest extends BaseIntegrationTest { @Autowired private UniversityQueryService universityQueryService; @@ -91,7 +92,7 @@ class UniversityQueryServiceTest extends UniversityDataSetUpIntegrationTest { } @Test - void 존재하지_않는_대학_상세정보_조회시_예외_응답을_반환한다() { + void 존재하지_않는_대학_상세정보를_조회하면_예외_응답을_반환한다() { // given Long invalidUniversityInfoForApplyId = 9999L; diff --git a/src/test/java/com/example/solidconnection/university/service/UniversityRecommendServiceTest.java b/src/test/java/com/example/solidconnection/university/service/UniversityRecommendServiceTest.java index 1fee99033..cadd45aaf 100644 --- a/src/test/java/com/example/solidconnection/university/service/UniversityRecommendServiceTest.java +++ b/src/test/java/com/example/solidconnection/university/service/UniversityRecommendServiceTest.java @@ -6,6 +6,7 @@ import com.example.solidconnection.repositories.InterestedRegionRepository; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import com.example.solidconnection.support.integration.BaseIntegrationTest; import com.example.solidconnection.type.Gender; import com.example.solidconnection.type.PreparationStatus; import com.example.solidconnection.type.Role; @@ -22,7 +23,7 @@ import static org.assertj.core.api.Assertions.assertThat; @DisplayName("대학교 추천 서비스 테스트") -class UniversityRecommendServiceTest extends UniversityDataSetUpIntegrationTest { +class UniversityRecommendServiceTest extends BaseIntegrationTest { @Autowired private UniversityRecommendService universityRecommendService;