From 8feb7a09ae77efed532b0d9cd30f1652bce1d752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Fri, 24 May 2024 09:03:18 +0900 Subject: [PATCH] =?UTF-8?q?Feat=20[#22]=20=ED=95=84=ED=84=B0=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=EC=97=90=20=EB=8C=80=ED=95=9C=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. testFindFilteredPositionsByKeyword: 유효한 키워드와 카테고리 ID가 제공될 때 메서드가 정확하게 포지션을 반환하는지 검증합니다. 이 테스트는 키워드 "1"로 검색했을 때 "[토스 뱅크] System Engineer" 포지션이 올바르게 가져오는지 확인합니다. 2. testFindPositionsByKeyword_Failure: 제공된 키워드와 카테고리 ID에 맞는 포지션이 발견되지 않을 때 RuntimeException이 발생하도록 보장합니다. 이 테스트는 검색 결과가 없는 경우를 적절히 처리하고 오류 메시지 "[ERROR] 채용 공고 검색에 실패하였습니다."가 반환되는지 검증합니다. --- .../position/service/PositionServiceTest.java | 115 +++++++++++++++--- 1 file changed, 96 insertions(+), 19 deletions(-) diff --git a/jumpit/src/test/java/org/sopt/jumpit/position/service/PositionServiceTest.java b/jumpit/src/test/java/org/sopt/jumpit/position/service/PositionServiceTest.java index e4cc5d8..535d413 100644 --- a/jumpit/src/test/java/org/sopt/jumpit/position/service/PositionServiceTest.java +++ b/jumpit/src/test/java/org/sopt/jumpit/position/service/PositionServiceTest.java @@ -12,17 +12,22 @@ import org.sopt.jumpit.position.domain.Position; import org.sopt.jumpit.position.dto.PositionsFindResponse; import org.sopt.jumpit.position.repository.PositionRepository; +import org.sopt.jumpit.relationship.domain.PositionCategory; +import org.sopt.jumpit.relationship.service.PositionCategoryService; import org.sopt.jumpit.skill.domain.Skill; import org.sopt.jumpit.skill.service.SkillService; import java.lang.reflect.Field; +import java.util.Arrays; import java.util.List; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) public class PositionServiceTest { @@ -39,15 +44,18 @@ public class PositionServiceTest { @Mock private Company mockCompany; + @Mock + private PositionCategoryService positionCategoryService; + @Test - @DisplayName("키워드 '백엔드 개발자'로 검색할 때 포지션 찾기: 성공 시 결과가 포함된 리스트 반환") + @DisplayName("키워드 '백엔드 개발자'로 검색 시, 해당 키워드를 포함하는 포지션 리스트 반환") void testFindPositionsByKeyword_Success() throws NoSuchFieldException, IllegalAccessException { // Given: "백엔드 개발자" 키워드로 포지션을 찾기 위한 설정 - Position samplePosition = createPositionWithReflection(1L, "백엔드 개발자", mockCompany); + Position samplePosition = createPositionByKeywordWithReflection(1L, "백엔드 개발자", mockCompany); when(positionRepository.findPositionsByTitleContaining("백엔드 개발자")) .thenReturn(Optional.of(List.of(samplePosition))); - Skill javaSkill = createSkillWithReflection("Java", "java.png"); + Skill javaSkill = createSkillByKeywordWithReflection("Java", "https://drive.google.com/file/d/1TliH1yADLU_2pmpy6PjavnkqWjdJ9MGa/view?usp=drive_link"); when(skillService.findByOwnerId(anyLong())) .thenReturn(List.of(javaSkill)); // 스킬 리스트를 반환하는 설정 @@ -59,21 +67,8 @@ void testFindPositionsByKeyword_Success() throws NoSuchFieldException, IllegalAc assertThat(result.position().get(0).title()).isEqualTo("백엔드 개발자"); } - @Test - @DisplayName("키워드 '채은아 생일 축하해'로 검색할 때 포지션 없음: 예외 발생하여 테스트 성공") - void testFindPositionsByKeyword_NotFound() { - // Given: "Nonexistent" 키워드로 포지션을 찾지 못할 때의 설정 - when(positionRepository.findPositionsByTitleContaining("채은아 생일 축하해")) - .thenReturn(Optional.empty()); - - // Then: 예외가 발생하면 테스트 성공으로 간주 - assertThatThrownBy(() -> positionService.findPositionsByKeyword("채은아 생일 축하해")) - .isInstanceOf(NotFoundException.class) - .hasMessageContaining(ErrorMessage.SEARCH_FAILED.getMessage()); - } - // 리플렉션을 사용하여 Position 객체 생성 - private Position createPositionWithReflection(Long id, String title, Company company) throws NoSuchFieldException, IllegalAccessException { + private Position createPositionByKeywordWithReflection(Long id, String title, Company company) throws NoSuchFieldException, IllegalAccessException { Position position = new Position(); Field idField = position.getClass().getDeclaredField("id"); idField.setAccessible(true); @@ -91,7 +86,7 @@ private Position createPositionWithReflection(Long id, String title, Company com } // 리플렉션을 사용하여 Skill 객체 생성 - private Skill createSkillWithReflection(String name, String image) throws NoSuchFieldException, IllegalAccessException { + private Skill createSkillByKeywordWithReflection(String name, String image) throws NoSuchFieldException, IllegalAccessException { Skill skill = new Skill(); Field nameField = skill.getClass().getDeclaredField("name"); nameField.setAccessible(true); @@ -103,4 +98,86 @@ private Skill createSkillWithReflection(String name, String image) throws NoSuch return skill; } + + @Test + @DisplayName("존재하지 않는 키워드로 검색 시, NotFoundException 발생") + void testFindPositionsByKeyword_NotFound() { + // Given: "Nonexistent" 키워드로 포지션을 찾지 못할 때의 설정 + when(positionRepository.findPositionsByTitleContaining("채은아 생일 축하해")) + .thenReturn(Optional.empty()); + + // Then: 예외가 발생하면 테스트 성공으로 간주 + assertThatThrownBy(() -> positionService.findPositionsByKeyword("채은아 생일 축하해")) + .isInstanceOf(NotFoundException.class) + .hasMessageContaining(ErrorMessage.SEARCH_FAILED.getMessage()); + } + + @Test + @DisplayName("키워드와 카테고리에 따라 필터링된 포지션 목록 조회") + void testFindFilteredPositionsByKeyword() { + // Given: "1" 키워드와 카테고리 ID 목록을 설정하여 포지션 필터링을 위한 준비 + // "1" 키워드로 포지션을 검색할 때 사용될 예상 키워드와 카테고리 목록을 설정 + String keyword = "1"; + List categoryIds = Arrays.asList(1L, 2L); + + // Position 객체를 목킹하여, "[토스 뱅크] System Engineer"라는 제목과 함께 설정 + Position position1 = mock(Position.class); + when(position1.getId()).thenReturn(1L); + when(position1.getTitle()).thenReturn("[토스 뱅크] System Engineer"); + + // Company 객체도 목킹하여, 해당 포지션의 회사 정보 반환 설정 + Company mockCompany = mock(Company.class); + when(mockCompany.getId()).thenReturn(10L); + when(position1.getCompany()).thenReturn(mockCompany); + + // Skill 객체를 목킹하여, "Java"라는 기술 스택 정보 반환 설정 + Skill skill = mock(Skill.class); + when(skill.getName()).thenReturn("Java"); + when(skill.getImage()).thenReturn("https://drive.google.com/file/d/1TliH1yADLU_2pmpy6PjavnkqWjdJ9MGa/view?usp=drive_link"); + + // PositionCategoryService에서 카테고리 ID에 따라 PositionCategory 객체 목 리스트를 반환하도록 설정 + PositionCategory positionCategoryMock = mock(PositionCategory.class); + when(positionCategoryMock.getPosition()).thenReturn(position1); + when(positionCategoryService.findPositionByCategory(anyLong())).thenReturn(Arrays.asList(positionCategoryMock)); + + // PositionRepository에서 제공된 키워드를 포함하는 포지션 목록을 반환하도록 설정 + when(positionRepository.findPositionsByTitleContaining(anyString())).thenReturn(Optional.of(List.of(position1))); + when(skillService.findByOwnerId(anyLong())).thenReturn(List.of(skill)); + + // When: 실제 검색 메서드를 실행하여 결과를 받음 + PositionsFindResponse result = positionService.findFilteredPositionsByKeyword(keyword, categoryIds); + + // Then: 결과 검증, "[토스 뱅크] System Engineer" 포지션을 정확하게 반환했는지 확인 + assertThat(result.position()).hasSize(1); + assertThat(result.position().get(0).title()).isEqualTo("[토스 뱅크] System Engineer"); + + // Verify: 각 서비스의 메서드가 예상대로 호출되었는지 검증 + verify(positionCategoryService, times(categoryIds.size())).findPositionByCategory(anyLong()); + verify(positionRepository).findPositionsByTitleContaining(keyword.trim()); + verify(skillService).findByOwnerId(position1.getId()); + } + + @Test + @DisplayName("키워드와 카테고리로 포지션을 찾지 못했을 때 예외를 발생시키는 실패 테스트") + void testFindPositionsByKeyword_Failure() { + // Given: "1" 키워드와 ID 1, 2로 구성된 카테고리 목록으로 설정 + String keyword = "1"; + List categoryIds = Arrays.asList(1L, 2L); + + // PositionRepository에서 해당 키워드를 포함하는 포지션 목록이 없는 상황 설정 (빈 Optional 반환) + when(positionRepository.findPositionsByTitleContaining(keyword)).thenReturn(Optional.empty()); + + // When: 해당 키워드로 포지션 검색을 시도하고 결과가 없을 경우 RuntimeException을 예상 + RuntimeException exception = assertThrows(RuntimeException.class, () -> { + positionService.findFilteredPositionsByKeyword(keyword, categoryIds); + }); + + // Then: 예외 발생을 확인하고, "포지션을 찾을 수 없습니다" 메시지가 포함되어 있는지 검증 + assertThat(exception.getMessage()).contains("[ERROR] 채용 공고 검색에 실패하였습니다."); + + // Verify: PositionRepository의 findPositionsByTitleContaining 메서드가 호출됨을 확인 + verify(positionRepository).findPositionsByTitleContaining(keyword.trim()); + verifyNoInteractions(skillService); // 검색 결과가 없으므로 SkillService는 호출되지 않음 + } + }