From 1f1aca6036373b8cc110fba9b32fd6c004c511b1 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 19 Aug 2025 18:50:17 +0900 Subject: [PATCH 1/8] =?UTF-8?q?refactor:=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EA=B5=AC=ED=98=84=EC=B2=B4=EA=B0=80=20?= =?UTF-8?q?=EC=95=84=EB=8B=88=EB=9D=BC=20=EC=9D=B8=ED=84=B0=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EC=9D=98=EC=A1=B4=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UnivApplyInfoFilterRepositoryImpl가 아니라 UnivApplyInfoRepository를 의존하게 한다. - 그렇게 해도 되는 이유는, UnivApplyInfoRepository가 UnivApplyInfoFilterRepository를 extend하고 있기 때문 --- .../service/UnivApplyInfoQueryService.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/example/solidconnection/university/service/UnivApplyInfoQueryService.java b/src/main/java/com/example/solidconnection/university/service/UnivApplyInfoQueryService.java index ff0215c63..5dbd7dab2 100644 --- a/src/main/java/com/example/solidconnection/university/service/UnivApplyInfoQueryService.java +++ b/src/main/java/com/example/solidconnection/university/service/UnivApplyInfoQueryService.java @@ -8,7 +8,6 @@ import com.example.solidconnection.university.dto.UnivApplyInfoPreviewResponse; import com.example.solidconnection.university.dto.UnivApplyInfoPreviewResponses; import com.example.solidconnection.university.repository.UnivApplyInfoRepository; -import com.example.solidconnection.university.repository.custom.UnivApplyInfoFilterRepositoryImpl; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; @@ -20,7 +19,6 @@ public class UnivApplyInfoQueryService { private final UnivApplyInfoRepository univApplyInfoRepository; - private final UnivApplyInfoFilterRepositoryImpl universityFilterRepository; // todo: 구현체 숨기고 univApplyInfoRepository만 사용하도록 @Value("${university.term}") public String term; @@ -49,12 +47,13 @@ public UnivApplyInfoDetailResponse getUnivApplyInfoDetail(Long univApplyInfoId) @Transactional(readOnly = true) @ThunderingHerdCaching(key = "univApplyInfo:{0}:{1}:{2}:{3}", cacheManager = "customCacheManager", ttlSec = 86400) public UnivApplyInfoPreviewResponses searchUnivApplyInfo( - String regionCode, List keywords, LanguageTestType testType, String testScore) { - - return new UnivApplyInfoPreviewResponses(universityFilterRepository - .findAllByRegionCodeAndKeywordsAndLanguageTestTypeAndTestScoreAndTerm(regionCode, keywords, testType, testScore, term) - .stream() - .map(UnivApplyInfoPreviewResponse::from) - .toList()); + String regionCode, List keywords, LanguageTestType testType, String testScore + ) { + List res = univApplyInfoRepository + .findAllByRegionCodeAndKeywordsAndLanguageTestTypeAndTestScoreAndTerm(regionCode, keywords, testType, testScore, term) + .stream() + .map(UnivApplyInfoPreviewResponse::from) + .toList(); + return new UnivApplyInfoPreviewResponses(res); } } From c5f21713032d23f0d1d216492912c17aa3091a7b Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 20 Aug 2025 20:52:45 +0900 Subject: [PATCH 2/8] =?UTF-8?q?refactor:=20API=20=EB=AA=85=EC=84=B8?= =?UTF-8?q?=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC,=20=EC=9A=94=EC=B2=AD=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/UnivApplyInfoController.java | 28 ++++++++++------- .../dto/UnivApplyInfoFilterSearchRequest.java | 15 ++++++++++ .../service/UnivApplyInfoQueryService.java | 30 +++++++------------ 3 files changed, 42 insertions(+), 31 deletions(-) create mode 100644 src/main/java/com/example/solidconnection/university/dto/UnivApplyInfoFilterSearchRequest.java diff --git a/src/main/java/com/example/solidconnection/university/controller/UnivApplyInfoController.java b/src/main/java/com/example/solidconnection/university/controller/UnivApplyInfoController.java index c3b986d40..97adc128a 100644 --- a/src/main/java/com/example/solidconnection/university/controller/UnivApplyInfoController.java +++ b/src/main/java/com/example/solidconnection/university/controller/UnivApplyInfoController.java @@ -1,19 +1,22 @@ package com.example.solidconnection.university.controller; import com.example.solidconnection.common.resolver.AuthorizedUser; -import com.example.solidconnection.university.domain.LanguageTestType; import com.example.solidconnection.university.dto.IsLikeResponse; import com.example.solidconnection.university.dto.UnivApplyInfoDetailResponse; +import com.example.solidconnection.university.dto.UnivApplyInfoFilterSearchRequest; import com.example.solidconnection.university.dto.UnivApplyInfoPreviewResponse; +import com.example.solidconnection.university.dto.UnivApplyInfoPreviewResponses; import com.example.solidconnection.university.dto.UnivApplyInfoRecommendsResponse; import com.example.solidconnection.university.service.LikedUnivApplyInfoService; import com.example.solidconnection.university.service.UnivApplyInfoQueryService; import com.example.solidconnection.university.service.UnivApplyInfoRecommendService; +import jakarta.validation.Valid; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -84,16 +87,19 @@ public ResponseEntity getUnivApplyInfoDetails( return ResponseEntity.ok(univApplyInfoDetailResponse); } - // todo: return타입 UniversityInfoForApplyPreviewResponses로 추후 수정 필요 - @GetMapping("/search") - public ResponseEntity> searchUnivApplyInfo( - @RequestParam(required = false, defaultValue = "") String region, - @RequestParam(required = false, defaultValue = "") List keyword, - @RequestParam(required = false, defaultValue = "") LanguageTestType testType, - @RequestParam(required = false, defaultValue = "") String testScore + @GetMapping("/search/filter") + public ResponseEntity searchUnivApplyInfoByFilter( + @Valid @ModelAttribute UnivApplyInfoFilterSearchRequest request ) { - List univApplyInfoPreviewResponse - = univApplyInfoQueryService.searchUnivApplyInfo(region, keyword, testType, testScore).univApplyInfoPreviews(); - return ResponseEntity.ok(univApplyInfoPreviewResponse); + UnivApplyInfoPreviewResponses response = univApplyInfoQueryService.searchUnivApplyInfoByFilter(request); + return ResponseEntity.ok(response); + } + + @GetMapping("/search/text") + public ResponseEntity searchUnivApplyInfoByText( + @RequestParam(required = false) String text + ) { + UnivApplyInfoPreviewResponses response = univApplyInfoQueryService.searchUnivApplyInfoByText(text); + return ResponseEntity.ok(response); } } diff --git a/src/main/java/com/example/solidconnection/university/dto/UnivApplyInfoFilterSearchRequest.java b/src/main/java/com/example/solidconnection/university/dto/UnivApplyInfoFilterSearchRequest.java new file mode 100644 index 000000000..a49079319 --- /dev/null +++ b/src/main/java/com/example/solidconnection/university/dto/UnivApplyInfoFilterSearchRequest.java @@ -0,0 +1,15 @@ +package com.example.solidconnection.university.dto; + +import com.example.solidconnection.university.domain.LanguageTestType; +import jakarta.validation.constraints.NotNull; +import java.util.List; + +public record UnivApplyInfoFilterSearchRequest( + + @NotNull(message = "어학 시험 종류를 선택해주세요.") + LanguageTestType languageTestType, + String testScore, + List countryCode +) { + +} diff --git a/src/main/java/com/example/solidconnection/university/service/UnivApplyInfoQueryService.java b/src/main/java/com/example/solidconnection/university/service/UnivApplyInfoQueryService.java index 5dbd7dab2..77c6d2d25 100644 --- a/src/main/java/com/example/solidconnection/university/service/UnivApplyInfoQueryService.java +++ b/src/main/java/com/example/solidconnection/university/service/UnivApplyInfoQueryService.java @@ -1,14 +1,12 @@ package com.example.solidconnection.university.service; import com.example.solidconnection.cache.annotation.ThunderingHerdCaching; -import com.example.solidconnection.university.domain.LanguageTestType; import com.example.solidconnection.university.domain.UnivApplyInfo; import com.example.solidconnection.university.domain.University; import com.example.solidconnection.university.dto.UnivApplyInfoDetailResponse; -import com.example.solidconnection.university.dto.UnivApplyInfoPreviewResponse; +import com.example.solidconnection.university.dto.UnivApplyInfoFilterSearchRequest; import com.example.solidconnection.university.dto.UnivApplyInfoPreviewResponses; import com.example.solidconnection.university.repository.UnivApplyInfoRepository; -import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -37,23 +35,15 @@ public UnivApplyInfoDetailResponse getUnivApplyInfoDetail(Long univApplyInfoId) return UnivApplyInfoDetailResponse.of(university, univApplyInfo); } - /* - * 대학교 검색 결과를 불러온다. - * - 권역, 키워드, 언어 시험 종류, 언어 시험 점수를 조건으로 검색하여 결과를 반환한다. - * - 권역은 영어 대문자로 받는다 e.g. ASIA - * - 키워드는 국가명 또는 대학명에 포함되는 것이 조건이다. - * - 언어 시험 점수는 합격 최소 점수보다 높은 것이 조건이다. - * */ @Transactional(readOnly = true) - @ThunderingHerdCaching(key = "univApplyInfo:{0}:{1}:{2}:{3}", cacheManager = "customCacheManager", ttlSec = 86400) - public UnivApplyInfoPreviewResponses searchUnivApplyInfo( - String regionCode, List keywords, LanguageTestType testType, String testScore - ) { - List res = univApplyInfoRepository - .findAllByRegionCodeAndKeywordsAndLanguageTestTypeAndTestScoreAndTerm(regionCode, keywords, testType, testScore, term) - .stream() - .map(UnivApplyInfoPreviewResponse::from) - .toList(); - return new UnivApplyInfoPreviewResponses(res); + public UnivApplyInfoPreviewResponses searchUnivApplyInfoByFilter(UnivApplyInfoFilterSearchRequest request) { + // todo: 구현 + return null; + } + + @Transactional(readOnly = true) + public UnivApplyInfoPreviewResponses searchUnivApplyInfoByText(String text) { + // todo: 구현 + return null; } } From ce63b5afe6d686b64e5f9ad3c4fcbc07a2a17a5e Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 20 Aug 2025 20:57:50 +0900 Subject: [PATCH 3/8] =?UTF-8?q?feat:=20=EB=8C=80=ED=95=99=EC=A7=80?= =?UTF-8?q?=EC=9B=90=EC=A0=95=EB=B3=B4=20=ED=95=84=ED=84=B0=EB=A7=81=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../custom/UnivApplyInfoFilterRepository.java | 3 +- .../UnivApplyInfoFilterRepositoryImpl.java | 73 +++++++++++++------ .../service/UnivApplyInfoQueryService.java | 10 ++- 3 files changed, 59 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/example/solidconnection/university/repository/custom/UnivApplyInfoFilterRepository.java b/src/main/java/com/example/solidconnection/university/repository/custom/UnivApplyInfoFilterRepository.java index 5c95e5d1e..9de0e98b6 100644 --- a/src/main/java/com/example/solidconnection/university/repository/custom/UnivApplyInfoFilterRepository.java +++ b/src/main/java/com/example/solidconnection/university/repository/custom/UnivApplyInfoFilterRepository.java @@ -8,6 +8,5 @@ public interface UnivApplyInfoFilterRepository { List findAllByRegionCodeAndKeywords(String regionCode, List keywords); - List findAllByRegionCodeAndKeywordsAndLanguageTestTypeAndTestScoreAndTerm( - String regionCode, List keywords, LanguageTestType testType, String testScore, String term); + List findAllByFilter(LanguageTestType testType, String testScore, String term, List countryKoreanNames); } diff --git a/src/main/java/com/example/solidconnection/university/repository/custom/UnivApplyInfoFilterRepositoryImpl.java b/src/main/java/com/example/solidconnection/university/repository/custom/UnivApplyInfoFilterRepositoryImpl.java index 9e57274ee..538074422 100644 --- a/src/main/java/com/example/solidconnection/university/repository/custom/UnivApplyInfoFilterRepositoryImpl.java +++ b/src/main/java/com/example/solidconnection/university/repository/custom/UnivApplyInfoFilterRepositoryImpl.java @@ -1,7 +1,6 @@ package com.example.solidconnection.university.repository.custom; import com.example.solidconnection.location.country.domain.QCountry; -import com.example.solidconnection.location.region.domain.QRegion; import com.example.solidconnection.university.domain.LanguageTestType; import com.example.solidconnection.university.domain.QLanguageRequirement; import com.example.solidconnection.university.domain.QUnivApplyInfo; @@ -70,43 +69,71 @@ private BooleanExpression createKeywordCondition(StringPath namePath, List findAllByRegionCodeAndKeywordsAndLanguageTestTypeAndTestScoreAndTerm( - String regionCode, List keywords, LanguageTestType testType, String testScore, String term) { + public List findAllByFilter( + LanguageTestType testType, String testScore, String term, List countryCodes + ) { QUniversity university = QUniversity.university; - QCountry country = QCountry.country; - QRegion region = QRegion.region; QUnivApplyInfo univApplyInfo = QUnivApplyInfo.univApplyInfo; + QCountry country = QCountry.country; + QLanguageRequirement languageRequirement = QLanguageRequirement.languageRequirement; - List filteredUnivApplyInfo = queryFactory - .selectFrom(univApplyInfo) + List filteredUnivApplyInfo = queryFactory.selectFrom(univApplyInfo) .join(univApplyInfo.university, university) .join(university.country, country) - .join(university.region, region) - .where(regionCodeEq(country, regionCode) - .and(countryOrUniversityContainsKeyword(country, university, keywords)) - .and(univApplyInfo.term.eq(term))) + .join(univApplyInfo.languageRequirements, languageRequirement) + .fetchJoin() + .where( + languageTestTypeEq(languageRequirement, testType), + termEq(univApplyInfo, term), + countryCodesIn(country, countryCodes) + ) + .distinct() .fetch(); - if (testScore == null || testScore.isEmpty()) { - if (testType != null) { - return filteredUnivApplyInfo.stream() - .filter(uai -> uai.getLanguageRequirements().stream() - .anyMatch(lr -> lr.getLanguageTestType().equals(testType))) - .toList(); - } + if (testScore == null || testScore.isBlank()) { return filteredUnivApplyInfo; } + /* + * 시험 유형에 따라 성적 비교 방식이 다르다. + * 입력된 점수가 대학에서 요구하는 최소 점수보다 높은지를 '쿼리로' 비교하기엔 쿼리가 지나치게 복잡해진다. + * 따라서 이 부분만 자바 코드로 필터링한다. + * */ return filteredUnivApplyInfo.stream() - .filter(uai -> compareMyTestScoreToMinPassScore(uai, testType, testScore) >= 0) + .filter(uai -> isGivenScoreOverMinPassScore(uai, testType, testScore)) .toList(); } - private int compareMyTestScoreToMinPassScore(UnivApplyInfo univApplyInfo, LanguageTestType testType, String testScore) { + private BooleanExpression languageTestTypeEq( + QLanguageRequirement languageRequirement, LanguageTestType givenTestType + ) { + if (givenTestType == null) { + return null; + } + return languageRequirement.languageTestType.eq(givenTestType); + } + + private BooleanExpression termEq(QUnivApplyInfo univApplyInfo, String givenTerm) { + if (givenTerm == null || givenTerm.isBlank()) { + return null; + } + return univApplyInfo.term.eq(givenTerm); + } + + private BooleanExpression countryCodesIn(QCountry country, List givenCountryCodes) { + if (givenCountryCodes == null || givenCountryCodes.isEmpty()) { + return null; + } + return country.code.in(givenCountryCodes); + } + + private boolean isGivenScoreOverMinPassScore( + UnivApplyInfo univApplyInfo, LanguageTestType givenTestType, String givenTestScore + ) { return univApplyInfo.getLanguageRequirements().stream() - .filter(languageRequirement -> languageRequirement.getLanguageTestType().equals(testType)) + .filter(languageRequirement -> languageRequirement.getLanguageTestType().equals(givenTestType)) .findFirst() - .map(requirement -> testType.compare(testScore, requirement.getMinScore())) - .orElse(-1); + .map(requirement -> givenTestType.compare(givenTestScore, requirement.getMinScore())) + .orElse(-1) >= 0; } } diff --git a/src/main/java/com/example/solidconnection/university/service/UnivApplyInfoQueryService.java b/src/main/java/com/example/solidconnection/university/service/UnivApplyInfoQueryService.java index 77c6d2d25..e8ba3140b 100644 --- a/src/main/java/com/example/solidconnection/university/service/UnivApplyInfoQueryService.java +++ b/src/main/java/com/example/solidconnection/university/service/UnivApplyInfoQueryService.java @@ -5,8 +5,10 @@ import com.example.solidconnection.university.domain.University; import com.example.solidconnection.university.dto.UnivApplyInfoDetailResponse; import com.example.solidconnection.university.dto.UnivApplyInfoFilterSearchRequest; +import com.example.solidconnection.university.dto.UnivApplyInfoPreviewResponse; import com.example.solidconnection.university.dto.UnivApplyInfoPreviewResponses; import com.example.solidconnection.university.repository.UnivApplyInfoRepository; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -37,8 +39,12 @@ public UnivApplyInfoDetailResponse getUnivApplyInfoDetail(Long univApplyInfoId) @Transactional(readOnly = true) public UnivApplyInfoPreviewResponses searchUnivApplyInfoByFilter(UnivApplyInfoFilterSearchRequest request) { - // todo: 구현 - return null; + List responses = univApplyInfoRepository + .findAllByFilter(request.languageTestType(), request.testScore(), term, request.countryCode()) + .stream() + .map(UnivApplyInfoPreviewResponse::from) + .toList(); + return new UnivApplyInfoPreviewResponses(responses); } @Transactional(readOnly = true) From 0273f67ab198789e902e2067de8a704b0583908b Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 20 Aug 2025 21:16:06 +0900 Subject: [PATCH 4/8] =?UTF-8?q?chore:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../university/repository/UniversityRepository.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/com/example/solidconnection/university/repository/UniversityRepository.java b/src/main/java/com/example/solidconnection/university/repository/UniversityRepository.java index 5447a14ba..15210c18d 100644 --- a/src/main/java/com/example/solidconnection/university/repository/UniversityRepository.java +++ b/src/main/java/com/example/solidconnection/university/repository/UniversityRepository.java @@ -4,16 +4,10 @@ import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.university.domain.University; -import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; public interface UniversityRepository extends JpaRepository { - @Query("SELECT u FROM University u WHERE u.country.code IN :countryCodes OR u.region.code IN :regionCodes") - List findByCountryCodeInOrRegionCodeIn(@Param("countryCodes") List countryCodes, @Param("regionCodes") List regionCodes); - default University getUniversityById(Long id) { return findById(id) .orElseThrow(() -> new CustomException(UNIVERSITY_NOT_FOUND)); From 816f9f80cbd57f8b706ad6ed989c1b718334e8c5 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 20 Aug 2025 21:39:01 +0900 Subject: [PATCH 5/8] =?UTF-8?q?refactor:=20=EB=9E=8C=EB=8B=A4=20=ED=91=9C?= =?UTF-8?q?=ED=98=84=EC=8B=9D=20=EA=B0=84=EC=86=8C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../solidconnection/university/domain/LanguageTestType.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/solidconnection/university/domain/LanguageTestType.java b/src/main/java/com/example/solidconnection/university/domain/LanguageTestType.java index f220ac3d3..31cd09e62 100644 --- a/src/main/java/com/example/solidconnection/university/domain/LanguageTestType.java +++ b/src/main/java/com/example/solidconnection/university/domain/LanguageTestType.java @@ -4,8 +4,8 @@ public enum LanguageTestType { - CEFR((s1, s2) -> s1.compareTo(s2)), - JLPT((s1, s2) -> s2.compareTo(s1)), + CEFR(String::compareTo), + JLPT(Comparator.reverseOrder()), DALF(LanguageTestType::compareIntegerScores), DELF(LanguageTestType::compareIntegerScores), DUOLINGO(LanguageTestType::compareIntegerScores), From 303ee8d3670c4a9ce81d3e4a38cdaf903692bf92 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 20 Aug 2025 21:39:19 +0900 Subject: [PATCH 6/8] =?UTF-8?q?chore:=20=EC=A3=BC=EC=84=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - compare 에서 0은 같다는 의미 --- .../solidconnection/university/domain/LanguageTestType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/solidconnection/university/domain/LanguageTestType.java b/src/main/java/com/example/solidconnection/university/domain/LanguageTestType.java index 31cd09e62..af0f861db 100644 --- a/src/main/java/com/example/solidconnection/university/domain/LanguageTestType.java +++ b/src/main/java/com/example/solidconnection/university/domain/LanguageTestType.java @@ -16,7 +16,7 @@ public enum LanguageTestType { TOEFL_IBT(LanguageTestType::compareIntegerScores), TOEFL_ITP(LanguageTestType::compareIntegerScores), TOEIC(LanguageTestType::compareIntegerScores), - ETC((s1, s2) -> 0), // 기타 언어시험은 점수를 비교할 수 없으므로 항상 크다고 비교한다. + ETC((s1, s2) -> 0), // 기타 언어시험은 점수를 비교할 수 없으므로 항상 같다고 비교한다. ; private final Comparator comparator; From f3476fb9f211abc16b7ea57028a538dedde2723c Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 20 Aug 2025 21:40:01 +0900 Subject: [PATCH 7/8] =?UTF-8?q?test:=20=EB=B0=94=EB=80=90=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=EC=9D=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=EC=97=90=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UnivApplyInfoQueryServiceTest.java | 269 +++++++----------- 1 file changed, 107 insertions(+), 162 deletions(-) diff --git a/src/test/java/com/example/solidconnection/university/service/UnivApplyInfoQueryServiceTest.java b/src/test/java/com/example/solidconnection/university/service/UnivApplyInfoQueryServiceTest.java index fd6b4b26d..800329e3d 100644 --- a/src/test/java/com/example/solidconnection/university/service/UnivApplyInfoQueryServiceTest.java +++ b/src/test/java/com/example/solidconnection/university/service/UnivApplyInfoQueryServiceTest.java @@ -1,24 +1,26 @@ package com.example.solidconnection.university.service; import static com.example.solidconnection.common.exception.ErrorCode.UNIV_APPLY_INFO_NOT_FOUND; +import static com.example.solidconnection.university.domain.LanguageTestType.TOEIC; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.mockito.BDDMockito.then; import static org.mockito.Mockito.times; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.support.TestContainerSpringBootTest; -import com.example.solidconnection.university.domain.LanguageTestType; import com.example.solidconnection.university.domain.UnivApplyInfo; import com.example.solidconnection.university.dto.UnivApplyInfoDetailResponse; +import com.example.solidconnection.university.dto.UnivApplyInfoFilterSearchRequest; import com.example.solidconnection.university.dto.UnivApplyInfoPreviewResponse; import com.example.solidconnection.university.dto.UnivApplyInfoPreviewResponses; import com.example.solidconnection.university.fixture.LanguageRequirementFixture; import com.example.solidconnection.university.fixture.UnivApplyInfoFixture; import com.example.solidconnection.university.repository.UnivApplyInfoRepository; -import com.example.solidconnection.university.repository.custom.UnivApplyInfoFilterRepository; import java.util.List; 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.SpyBean; @@ -30,9 +32,6 @@ class UnivApplyInfoQueryServiceTest { @Autowired private UnivApplyInfoQueryService univApplyInfoQueryService; - @SpyBean - private UnivApplyInfoFilterRepository univApplyInfoFilterRepository; - @SpyBean private UnivApplyInfoRepository univApplyInfoRepository; @@ -42,164 +41,110 @@ class UnivApplyInfoQueryServiceTest { @Autowired private LanguageRequirementFixture languageRequirementFixture; - @Test - void 대학_지원_정보를_상세_조회한다() { - // given - UnivApplyInfo 괌대학_A_지원_정보 = univApplyInfoFixture.괌대학_A_지원_정보(); - - // when - UnivApplyInfoDetailResponse response = univApplyInfoQueryService.getUnivApplyInfoDetail(괌대학_A_지원_정보.getId()); - - // then - assertThat(response.id()).isEqualTo(괌대학_A_지원_정보.getId()); - } - - @Test - void 대학_지원_정보_상세_조회시_캐시가_적용된다() { - // given - UnivApplyInfo 괌대학_A_지원_정보 = univApplyInfoFixture.괌대학_A_지원_정보(); - - // when - UnivApplyInfoDetailResponse firstResponse = univApplyInfoQueryService.getUnivApplyInfoDetail(괌대학_A_지원_정보.getId()); - UnivApplyInfoDetailResponse secondResponse = univApplyInfoQueryService.getUnivApplyInfoDetail(괌대학_A_지원_정보.getId()); - - // then - assertThat(firstResponse).isEqualTo(secondResponse); - then(univApplyInfoRepository).should(times(1)).getUnivApplyInfoById(괌대학_A_지원_정보.getId()); - } - - @Test - void 존재하지_않는_대학_지원_정보를_조회하면_예외가_발생한다() { - // given - Long invalidUnivApplyInfoId = 9999L; - - // when & then - assertThatExceptionOfType(RuntimeException.class) - .isThrownBy(() -> univApplyInfoQueryService.getUnivApplyInfoDetail(invalidUnivApplyInfoId)) - .havingRootCause() - .isInstanceOf(CustomException.class) - .withMessage(UNIV_APPLY_INFO_NOT_FOUND.getMessage()); - } - - @Test - void 전체_대학_지원_정보를_조회한다() { - // given - UnivApplyInfo 괌대학_A_지원_정보 = univApplyInfoFixture.괌대학_A_지원_정보(); - UnivApplyInfo 괌대학_B_지원_정보 = univApplyInfoFixture.괌대학_B_지원_정보(); - UnivApplyInfo 네바다주립대학_라스베이거스_지원_정보 = univApplyInfoFixture.네바다주립대학_라스베이거스_지원_정보(); - UnivApplyInfo 서던덴마크대학교_지원_정보 = univApplyInfoFixture.서던덴마크대학교_지원_정보(); - UnivApplyInfo 그라츠대학_지원_정보 = univApplyInfoFixture.그라츠대학_지원_정보(); - UnivApplyInfo 메이지대학_지원_정보 = univApplyInfoFixture.메이지대학_지원_정보(); - - // when - UnivApplyInfoPreviewResponses response = univApplyInfoQueryService.searchUnivApplyInfo( - null, List.of(), null, null); - - // then - assertThat(response.univApplyInfoPreviews()) - .containsExactlyInAnyOrder( - UnivApplyInfoPreviewResponse.from(괌대학_A_지원_정보), - UnivApplyInfoPreviewResponse.from(괌대학_B_지원_정보), - UnivApplyInfoPreviewResponse.from(네바다주립대학_라스베이거스_지원_정보), - UnivApplyInfoPreviewResponse.from(서던덴마크대학교_지원_정보), - UnivApplyInfoPreviewResponse.from(그라츠대학_지원_정보), - UnivApplyInfoPreviewResponse.from(메이지대학_지원_정보) - ); - } - - @Test - void 대학_지원_정보_조회시_캐시가_적용된다() { - // given - univApplyInfoFixture.괌대학_A_지원_정보(); - String regionCode = "AMERICAS"; - List keywords = List.of("괌"); - LanguageTestType testType = LanguageTestType.TOEFL_IBT; - String testScore = "70"; - String term = "2024-1"; - - // when - UnivApplyInfoPreviewResponses firstResponse = - univApplyInfoQueryService.searchUnivApplyInfo(regionCode, keywords, testType, testScore); - UnivApplyInfoPreviewResponses secondResponse = - univApplyInfoQueryService.searchUnivApplyInfo(regionCode, keywords, testType, testScore); - - // then - assertThat(firstResponse).isEqualTo(secondResponse); - then(univApplyInfoFilterRepository).should(times(1)) - .findAllByRegionCodeAndKeywordsAndLanguageTestTypeAndTestScoreAndTerm( - regionCode, keywords, testType, testScore, term); - } - - @Test - void 지역으로_대학_지원_정보를_필터링한다() { - // given - UnivApplyInfo 괌대학_A_지원_정보 = univApplyInfoFixture.괌대학_A_지원_정보(); - univApplyInfoFixture.코펜하겐IT대학_지원_정보(); - univApplyInfoFixture.그라츠공과대학_지원_정보(); - univApplyInfoFixture.메이지대학_지원_정보(); - - // when - UnivApplyInfoPreviewResponses response = univApplyInfoQueryService.searchUnivApplyInfo( - "AMERICAS", List.of(), null, null); - - // then - assertThat(response.univApplyInfoPreviews()) - .containsExactlyInAnyOrder(UnivApplyInfoPreviewResponse.from(괌대학_A_지원_정보)); - } - - @Test - void 키워드로_대학_지원_정보를_필터링한다() { - // given - univApplyInfoFixture.괌대학_A_지원_정보(); - UnivApplyInfo 그라츠대학_지원_정보 = univApplyInfoFixture.그라츠대학_지원_정보(); - UnivApplyInfo 메이지대학_지원_정보 = univApplyInfoFixture.메이지대학_지원_정보(); - - // when - UnivApplyInfoPreviewResponses response = univApplyInfoQueryService.searchUnivApplyInfo( - null, List.of("라", "일본"), null, null); - - // then - assertThat(response.univApplyInfoPreviews()) - .containsExactlyInAnyOrder( - UnivApplyInfoPreviewResponse.from(그라츠대학_지원_정보), - UnivApplyInfoPreviewResponse.from(메이지대학_지원_정보) - ); - } - - @Test - void 어학시험_조건으로_대학_지원_정보를_필터링한다() { - // given - UnivApplyInfo 괌대학_A_지원_정보 = univApplyInfoFixture.괌대학_A_지원_정보(); - languageRequirementFixture.토플_80(괌대학_A_지원_정보); - languageRequirementFixture.토익_800(괌대학_A_지원_정보); - UnivApplyInfo 괌대학_B_지원_정보 = univApplyInfoFixture.괌대학_B_지원_정보(); - languageRequirementFixture.토플_70(괌대학_B_지원_정보); - languageRequirementFixture.토익_900(괌대학_B_지원_정보); - - // when - UnivApplyInfoPreviewResponses response = univApplyInfoQueryService.searchUnivApplyInfo( - null, List.of(), LanguageTestType.TOEFL_IBT, "70"); - - // then - assertThat(response.univApplyInfoPreviews()) - .containsExactlyInAnyOrder(UnivApplyInfoPreviewResponse.from(괌대학_B_지원_정보)); + @Nested + class 대학_지원_정보_상세_조회 { + + @Test + void 대학_지원_정보를_상세_조회한다() { + // given + UnivApplyInfo 괌대학_A_지원_정보 = univApplyInfoFixture.괌대학_A_지원_정보(); + + // when + UnivApplyInfoDetailResponse response = univApplyInfoQueryService.getUnivApplyInfoDetail(괌대학_A_지원_정보.getId()); + + // then + assertThat(response.id()).isEqualTo(괌대학_A_지원_정보.getId()); + } + + @Test + void 대학_지원_정보_상세_조회시_캐시가_적용된다() { + // given + UnivApplyInfo 괌대학_A_지원_정보 = univApplyInfoFixture.괌대학_A_지원_정보(); + + // when + UnivApplyInfoDetailResponse firstResponse = univApplyInfoQueryService.getUnivApplyInfoDetail(괌대학_A_지원_정보.getId()); + UnivApplyInfoDetailResponse secondResponse = univApplyInfoQueryService.getUnivApplyInfoDetail(괌대학_A_지원_정보.getId()); + + // then + assertThat(firstResponse).isEqualTo(secondResponse); + then(univApplyInfoRepository).should(times(1)).getUnivApplyInfoById(괌대학_A_지원_정보.getId()); + } + + @Test + void 존재하지_않는_대학_지원_정보를_조회하면_예외가_발생한다() { + // given + Long invalidUnivApplyInfoId = 9999L; + + // when & then + assertThatExceptionOfType(RuntimeException.class) + .isThrownBy(() -> univApplyInfoQueryService.getUnivApplyInfoDetail(invalidUnivApplyInfoId)) + .havingRootCause() + .isInstanceOf(CustomException.class) + .withMessage(UNIV_APPLY_INFO_NOT_FOUND.getMessage()); + } } - @Test - void 모든_조건으로_대학_지원_정보를_필터링한다() { - // given - UnivApplyInfo 괌대학_A_지원_정보 = univApplyInfoFixture.괌대학_A_지원_정보(); - languageRequirementFixture.토플_80(괌대학_A_지원_정보); - languageRequirementFixture.토익_800(괌대학_A_지원_정보); - UnivApplyInfo 서던덴마크대학교_지원_정보 = univApplyInfoFixture.서던덴마크대학교_지원_정보(); - languageRequirementFixture.토플_70(서던덴마크대학교_지원_정보); - - // when - UnivApplyInfoPreviewResponses response = univApplyInfoQueryService.searchUnivApplyInfo( - "EUROPE", List.of(), LanguageTestType.TOEFL_IBT, "70"); - - // then - assertThat(response.univApplyInfoPreviews()) - .containsExactly(UnivApplyInfoPreviewResponse.from(서던덴마크대학교_지원_정보)); + @Nested + class 대학_지원_정보_필터링_검색 { + + @Test + void 어학_시험_종류로_필터링한다() { + // given + UnivApplyInfoFilterSearchRequest request = new UnivApplyInfoFilterSearchRequest(TOEIC, null, null); + UnivApplyInfo 괌대학_A_지원_정보 = univApplyInfoFixture.괌대학_A_지원_정보(); + languageRequirementFixture.토익_800(괌대학_A_지원_정보); + UnivApplyInfo 괌대학_B_지원_정보 = univApplyInfoFixture.괌대학_B_지원_정보(); + languageRequirementFixture.토플_70(괌대학_B_지원_정보); + + // when + UnivApplyInfoPreviewResponses response = univApplyInfoQueryService.searchUnivApplyInfoByFilter(request); + + // then + assertThat(response.univApplyInfoPreviews()) + .containsExactly(UnivApplyInfoPreviewResponse.from(괌대학_A_지원_정보)); + } + + @Test + void 어학_시험_점수가_기준치_이상인_곳을_필터링한다() { + // given + UnivApplyInfoFilterSearchRequest request = new UnivApplyInfoFilterSearchRequest(TOEIC, "800", null); + UnivApplyInfo 괌대학_A_지원_정보 = univApplyInfoFixture.괌대학_A_지원_정보(); + languageRequirementFixture.토익_800(괌대학_A_지원_정보); + UnivApplyInfo 괌대학_B_지원_정보 = univApplyInfoFixture.괌대학_B_지원_정보(); + languageRequirementFixture.토익_900(괌대학_B_지원_정보); + + // when + UnivApplyInfoPreviewResponses response = univApplyInfoQueryService.searchUnivApplyInfoByFilter(request); + + // then + assertThat(response.univApplyInfoPreviews()) + .containsExactlyInAnyOrder(UnivApplyInfoPreviewResponse.from(괌대학_A_지원_정보)); + } + + @Test + void 국가_코드로_필터링한다() { + // given + UnivApplyInfoFilterSearchRequest request1 = new UnivApplyInfoFilterSearchRequest(TOEIC, null, List.of("US")); + UnivApplyInfoFilterSearchRequest request2 = new UnivApplyInfoFilterSearchRequest(TOEIC, null, List.of("US", "CA")); + UnivApplyInfo 괌대학_A_지원_정보 = univApplyInfoFixture.괌대학_A_지원_정보(); + languageRequirementFixture.토익_800(괌대학_A_지원_정보); + UnivApplyInfo 메모리얼대학_세인트존스_A_지원_정보 = univApplyInfoFixture.메모리얼대학_세인트존스_A_지원_정보(); + languageRequirementFixture.토익_800(메모리얼대학_세인트존스_A_지원_정보); + + // when + UnivApplyInfoPreviewResponses response1 = univApplyInfoQueryService.searchUnivApplyInfoByFilter(request1); + UnivApplyInfoPreviewResponses response2 = univApplyInfoQueryService.searchUnivApplyInfoByFilter(request2); + + // then + assertAll( + () -> assertThat(response1.univApplyInfoPreviews()) + .containsExactly(UnivApplyInfoPreviewResponse.from(괌대학_A_지원_정보)), + () -> assertThat(response2.univApplyInfoPreviews()) + .containsExactlyInAnyOrder( + UnivApplyInfoPreviewResponse.from(괌대학_A_지원_정보), + UnivApplyInfoPreviewResponse.from(메모리얼대학_세인트존스_A_지원_정보) + ) + ); + } } } From be19f529ab36108fcd4a8200eab399db40659f61 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Sat, 23 Aug 2025 11:46:38 +0900 Subject: [PATCH 8/8] =?UTF-8?q?test:=20=EB=8D=94=20=EC=97=84=EA=B2=A9?= =?UTF-8?q?=ED=95=9C=20=EA=B2=80=EC=A6=9D=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../university/service/UnivApplyInfoQueryServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/example/solidconnection/university/service/UnivApplyInfoQueryServiceTest.java b/src/test/java/com/example/solidconnection/university/service/UnivApplyInfoQueryServiceTest.java index 800329e3d..69fa9b619 100644 --- a/src/test/java/com/example/solidconnection/university/service/UnivApplyInfoQueryServiceTest.java +++ b/src/test/java/com/example/solidconnection/university/service/UnivApplyInfoQueryServiceTest.java @@ -118,7 +118,7 @@ class 대학_지원_정보_필터링_검색 { // then assertThat(response.univApplyInfoPreviews()) - .containsExactlyInAnyOrder(UnivApplyInfoPreviewResponse.from(괌대학_A_지원_정보)); + .containsExactly(UnivApplyInfoPreviewResponse.from(괌대학_A_지원_정보)); } @Test