diff --git a/src/main/java/studio/studioeye/domain/company_information/application/CompanyInformationService.java b/src/main/java/studio/studioeye/domain/company_information/application/CompanyInformationService.java index 599d691b..edd82cb1 100644 --- a/src/main/java/studio/studioeye/domain/company_information/application/CompanyInformationService.java +++ b/src/main/java/studio/studioeye/domain/company_information/application/CompanyInformationService.java @@ -378,7 +378,7 @@ public ApiResponse deleteCompanyBasicInformation() { public ApiResponse deleteCompanyIntroductionInformation() { List companyInformations = companyInformationRepository.findAll(); if (companyInformations.isEmpty()) { - ApiResponse.withError(ErrorCode.COMPANYINFORMATION_IS_EMPTY); + return ApiResponse.withError(ErrorCode.COMPANYINFORMATION_IS_EMPTY); } for (CompanyInformation companyInformation : companyInformations) { String fileName = companyInformation.getSloganImageFileName(); @@ -393,7 +393,7 @@ public ApiResponse deleteCompanyIntroductionInformation() { public ApiResponse deleteCompanyDetailInformation() { List companyInformations = companyInformationRepository.findAll(); if (companyInformations.isEmpty()) { - ApiResponse.withError(ErrorCode.COMPANYINFORMATION_IS_EMPTY); + return ApiResponse.withError(ErrorCode.COMPANYINFORMATION_IS_EMPTY); } CompanyInformation companyInformation = companyInformations.get(0); companyInformation.deleteCompanyDetailInformation(); diff --git a/src/main/java/studio/studioeye/domain/email/service/EmailService.java b/src/main/java/studio/studioeye/domain/email/service/EmailService.java index af7558b4..d072b83a 100644 --- a/src/main/java/studio/studioeye/domain/email/service/EmailService.java +++ b/src/main/java/studio/studioeye/domain/email/service/EmailService.java @@ -17,6 +17,9 @@ public class EmailService { // } public boolean sendEmail(String to, String subject, String text) { + if (to == null || to.isEmpty()) { + throw new IllegalArgumentException("Invalid recipient address"); + } int emailSize = calculateEmailSize(subject, text); if(emailSize > MAX_EMAIL_SIZE) { System.out.println("over size"); diff --git a/src/test/java/studio/studioeye/domain/CompanyInformationServiceTest.java b/src/test/java/studio/studioeye/domain/CompanyInformationServiceTest.java index fce59c3e..82756d23 100644 --- a/src/test/java/studio/studioeye/domain/CompanyInformationServiceTest.java +++ b/src/test/java/studio/studioeye/domain/CompanyInformationServiceTest.java @@ -1372,19 +1372,19 @@ void deleteCompanyIntroductionInformationSuccess() { verify(s3Adapter, times(1)).deleteFile(anyString()); // S3 파일 삭제 호출 확인 verify(companyInformationRepository, times(1)).save(any(CompanyInformation.class)); // 저장 호출 확인 } -// @Test -// @DisplayName("회사 소개 정보 삭제 실패 - 회사 정보 없음") -// void deleteCompanyIntroductionInformation_emptyCompany_returnsErrorResponse() { -// // given -// when(companyInformationRepository.findAll()).thenReturn(Collections.emptyList()); -// -// // when -// ApiResponse response = companyInformationService.deleteCompanyIntroductionInformation(); -// -// // then -// assertEquals(HttpStatus.BAD_REQUEST, response.getStatus()); -// assertEquals(ErrorCode.COMPANYINFORMATION_IS_EMPTY.getMessage(), response.getMessage()); -// } + @Test + @DisplayName("회사 소개 정보 삭제 실패 - 회사 정보 없음") + void deleteCompanyIntroductionInformation_emptyCompany_returnsErrorResponse() { + // given + when(companyInformationRepository.findAll()).thenReturn(Collections.emptyList()); + + // when + ApiResponse response = companyInformationService.deleteCompanyIntroductionInformation(); + + // then + assertEquals(HttpStatus.BAD_REQUEST, response.getStatus()); + assertEquals(ErrorCode.COMPANYINFORMATION_IS_EMPTY.getMessage(), response.getMessage()); + } @Test @DisplayName("회사 상세 정보 삭제 성공") void deleteCompanyDetailInformationSuccess() { @@ -1402,17 +1402,17 @@ void deleteCompanyDetailInformationSuccess() { assertEquals("회사 5가지 상세 정보를 성공적으로 삭제했습니다.", response.getMessage()); verify(companyInformationRepository, times(1)).save(any(CompanyInformation.class)); // 저장 호출 확인 } -// @Test -// @DisplayName("회사 상세 정보 삭제 실패 - 회사 정보 없음") -// void deleteCompanyDetailInformation_emptyCompany_returnsErrorResponse() { -// // given -// when(companyInformationRepository.findAll()).thenReturn(Collections.emptyList()); -// -// // when -// ApiResponse response = companyInformationService.deleteCompanyDetailInformation(); -// -// // then -// assertEquals(HttpStatus.BAD_REQUEST, response.getStatus()); -// assertEquals(ErrorCode.COMPANYINFORMATION_IS_EMPTY.getMessage(), response.getMessage()); -// } + @Test + @DisplayName("회사 상세 정보 삭제 실패 - 회사 정보 없음") + void deleteCompanyDetailInformation_emptyCompany_returnsErrorResponse() { + // given + when(companyInformationRepository.findAll()).thenReturn(Collections.emptyList()); + + // when + ApiResponse response = companyInformationService.deleteCompanyDetailInformation(); + + // then + assertEquals(HttpStatus.BAD_REQUEST, response.getStatus()); + assertEquals(ErrorCode.COMPANYINFORMATION_IS_EMPTY.getMessage(), response.getMessage()); + } } diff --git a/src/test/java/studio/studioeye/domain/ceo/application/CeoServiceTest.java b/src/test/java/studio/studioeye/domain/ceo/application/CeoServiceTest.java index 85172d5b..7f172598 100644 --- a/src/test/java/studio/studioeye/domain/ceo/application/CeoServiceTest.java +++ b/src/test/java/studio/studioeye/domain/ceo/application/CeoServiceTest.java @@ -24,7 +24,6 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; - @ExtendWith(MockitoExtension.class) public class CeoServiceTest { @InjectMocks diff --git a/src/test/java/studio/studioeye/domain/email/application/EmailServiceTest.java b/src/test/java/studio/studioeye/domain/email/application/EmailServiceTest.java new file mode 100644 index 00000000..272b27af --- /dev/null +++ b/src/test/java/studio/studioeye/domain/email/application/EmailServiceTest.java @@ -0,0 +1,71 @@ +package studio.studioeye.domain.email.application; + +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.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import studio.studioeye.domain.email.service.EmailService; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +public class EmailServiceTest { + + @InjectMocks + private EmailService emailService; // EmailService를 올바르게 주입 + + @Mock + private JavaMailSender javaMailSender; + + @Test + @DisplayName("이메일 전송 성공 테스트") + public void sendEmailSuccess() { + // given + String to = "test@example.com"; + String subject = "Test Subject"; + String text = "Test Body"; + // stub + doNothing().when(javaMailSender).send(any(SimpleMailMessage.class)); + // when + boolean result = emailService.sendEmail(to, subject, text); + // then + assertTrue(result, "이메일이 정상적으로 전송되어야 합니다."); + verify(javaMailSender, times(1)).send(any(SimpleMailMessage.class)); + } + + @Test + @DisplayName("이메일 전송 실패 테스트 - 크기 초과") + public void sendEmailFailDueToSize() { + // given + String to = "test@example.com"; + String subject = "This is a very long subject that will exceed the limit"; + String text = "A".repeat(25 * 1024 * 1024); // 25MB 이상의 텍스트 + // when + boolean result = emailService.sendEmail(to, subject, text); + // then + assertFalse(result, "이메일 크기가 초과된 경우 전송에 실패해야 합니다."); + verify(javaMailSender, never()).send(any(SimpleMailMessage.class)); + } + + @Test + @DisplayName("이메일 전송 실패 테스트 - 수신자 없음") + public void sendEmailFailNoRecipient() { + // given + String to = null; + String subject = "Test Subject"; + String text = "Test Body"; + // when + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + emailService.sendEmail(to, subject, text); + }); + // then + assertEquals("Invalid recipient address", exception.getMessage()); + verify(javaMailSender, never()).send(any(SimpleMailMessage.class)); + } +} diff --git a/src/test/java/studio/studioeye/domain/partner_information/application/PartnerInformationServiceTest.java b/src/test/java/studio/studioeye/domain/partner_information/application/PartnerInformationServiceTest.java index 061816e9..273a9c3e 100644 --- a/src/test/java/studio/studioeye/domain/partner_information/application/PartnerInformationServiceTest.java +++ b/src/test/java/studio/studioeye/domain/partner_information/application/PartnerInformationServiceTest.java @@ -79,28 +79,28 @@ void createPartnerInfoSuccess() throws IOException { Mockito.verify(partnerInformationRepository, times(1)).save(any(PartnerInformation.class)); } -// @Test -// @DisplayName("파트너 정보 생성 실패 테스트 - S3 업로드 실패") -// void createPartnerInfoFailDueToS3UploadFailure() throws IOException { -// // given -// CreatePartnerInfoServiceRequestDto requestDto = new CreatePartnerInfoServiceRequestDto( -// "PartnerName", -// true, -// "http://partner-link.com" -// ); -// // Mock S3 upload failure -// when(s3Adapter.uploadFile(any(MultipartFile.class))) -// .thenReturn(ApiResponse.withError(ErrorCode.ERROR_S3_UPDATE_OBJECT)); -// // when -// ApiResponse response = partnerInformationService.createPartnerInfo(requestDto, mockFile); -// -// // then -// assertNull(response.getData()); -// assertEquals(ErrorCode.ERROR_S3_UPDATE_OBJECT.getStatus(), response.getStatus()); -// assertEquals(ErrorCode.ERROR_S3_UPDATE_OBJECT.getMessage(), response.getMessage()); -// -// Mockito.verify(partnerInformationRepository, never()).save(any(PartnerInformation.class)); -// } + @Test + @DisplayName("파트너 정보 생성 실패 테스트 - S3 업로드 실패") + void createPartnerInfoFailDueToS3UploadFailure() throws IOException { + // given + CreatePartnerInfoServiceRequestDto requestDto = new CreatePartnerInfoServiceRequestDto( + "PartnerName", + true, + "http://partner-link.com" + ); + // Mock S3 upload failure + when(s3Adapter.uploadImage(any(MultipartFile.class))) + .thenReturn(ApiResponse.withError(ErrorCode.ERROR_S3_UPDATE_OBJECT)); + // when + ApiResponse response = partnerInformationService.createPartnerInfo(requestDto, mockFile); + + // then + assertNull(response.getData()); + assertEquals(ErrorCode.ERROR_S3_UPDATE_OBJECT.getStatus(), response.getStatus()); + assertEquals(ErrorCode.ERROR_S3_UPDATE_OBJECT.getMessage(), response.getMessage()); + + Mockito.verify(partnerInformationRepository, never()).save(any(PartnerInformation.class)); + } @Test @DisplayName("협력사 정보 목록 조회 성공 테스트") @@ -255,26 +255,48 @@ void retrievePartnerInformationPageFail() { verify(partnerInformationRepository, times(1)).findAll(pageable); } -// @Test -// @DisplayName("협력사 정보 업데이트 성공 테스트") -// void updatePartnerInfoSuccess() throws IOException { -// // given -// PartnerInformation partnerInformation = new PartnerInformation("Logo1", "Partner1", true, "http://link1.com"); -// UpdatePartnerInfoServiceRequestDto requestDto = new UpdatePartnerInfoServiceRequestDto(1L, "UpdatedName", true, "http://updated-link.com"); -// MockMultipartFile mockFile = new MockMultipartFile("file", "testImage.jpg", "image/jpeg", "Test Image Content".getBytes()); -// // stub -// when(partnerInformationRepository.findById(1L)).thenReturn(Optional.of(partnerInformation)); -// when(s3Adapter.uploadFile(any(MultipartFile.class))) -// .thenReturn(ApiResponse.ok("S3에 이미지 업로드 성공", "http://example.com/newTestImage.jpg")); -// when(s3Adapter.deleteFile(anyString())).thenReturn(ApiResponse.ok("S3에서 기존 이미지 삭제 성공")); -// -// // when -// ApiResponse response = partnerInformationService.updatePartnerInfo(requestDto, mockFile); -// -// // then -// assertEquals("UpdatedName", response.getData().getName()); -// assertEquals("http://example.com/newTestImage.jpg", response.getData().getLogoImageUrl()); -// } + @Test + @DisplayName("협력사 정보 업데이트 성공 테스트") + void updatePartnerInfoSuccess() throws IOException { + // given + Long validPartnerId = 1L; + String oldLogoImageUrl = "https://example-bucket.s3.amazonaws.com/path/to/old-logo.png"; + String newLogoImageUrl = "https://example-bucket.s3.amazonaws.com/path/to/new-logo.png"; + + PartnerInformation mockPartnerInformation = PartnerInformation.builder() + .name("Old Name") + .logoImageUrl(oldLogoImageUrl) + .is_main(false) + .link("http://old-link.com") + .build(); + + UpdatePartnerInfoServiceRequestDto dto = new UpdatePartnerInfoServiceRequestDto( + validPartnerId, + "New Name", + true, + "http://new-link.com" + ); + + MultipartFile mockFile = mock(MultipartFile.class); + + when(partnerInformationRepository.findById(validPartnerId)).thenReturn(Optional.of(mockPartnerInformation)); + when(s3Adapter.uploadImage(mockFile)).thenReturn(ApiResponse.ok("S3 버킷에 이미지 업로드를 성공하였습니다.", newLogoImageUrl)); + when(s3Adapter.deleteFile("path")).thenReturn(ApiResponse.ok("S3 버킷에서 이미지를 성공적으로 삭제하였습니다.")); + when(partnerInformationRepository.save(any(PartnerInformation.class))).thenAnswer(invocation -> invocation.getArgument(0)); + + // when + ApiResponse response = partnerInformationService.updatePartnerInfo(dto, mockFile); + + // then + assertEquals("협력사 정보를 성공적으로 수정했습니다.", response.getMessage()); + assertEquals("New Name", response.getData().getName()); + assertEquals(newLogoImageUrl, response.getData().getLogoImageUrl()); + assertEquals("http://new-link.com", response.getData().getLink()); + assertTrue(response.getData().getIs_main()); + verify(s3Adapter, times(1)).deleteFile("path"); + verify(s3Adapter, times(1)).uploadImage(mockFile); + verify(partnerInformationRepository, times(1)).save(any(PartnerInformation.class)); + } @Test @DisplayName("협력사 정보 업데이트 실패 테스트 - 유효하지 않은 협력사 ID") @@ -292,25 +314,25 @@ void updatePartnerInfoInvalidPartnerId() { assertEquals(ErrorCode.INVALID_PARTNER_INFORMATION_ID.getMessage(), response.getMessage()); } -// @Test -// @DisplayName("협력사 정보 업데이트 실패 테스트 - S3 이미지 업데이트 실패") -// void updatePartnerInfoS3UpdateFail() throws IOException { -// // given -// PartnerInformation partnerInformation = new PartnerInformation("Logo1", "Partner1", true, "http://link1.com"); -// UpdatePartnerInfoServiceRequestDto requestDto = new UpdatePartnerInfoServiceRequestDto(1L, "UpdatedName", true, "http://updated-link.com"); -// MockMultipartFile mockFile = new MockMultipartFile("file", "testImage.jpg", "image/jpeg", "Test Image Content".getBytes()); -// -// when(partnerInformationRepository.findById(1L)).thenReturn(Optional.of(partnerInformation)); -// when(s3Adapter.uploadFile(any(MultipartFile.class))) -// .thenReturn(ApiResponse.withError(ErrorCode.ERROR_S3_UPDATE_OBJECT)); -// -// // when -// ApiResponse response = partnerInformationService.updatePartnerInfo(requestDto, mockFile); -// -// // then -// assertEquals(ErrorCode.ERROR_S3_UPDATE_OBJECT.getStatus(), response.getStatus()); -// assertEquals(ErrorCode.ERROR_S3_UPDATE_OBJECT.getMessage(), response.getMessage()); -// } + @Test + @DisplayName("협력사 정보 업데이트 실패 테스트 - S3 이미지 업데이트 실패") + void updatePartnerInfoS3UpdateFail() throws IOException { + // given + PartnerInformation partnerInformation = new PartnerInformation("Logo1", "Partner1", true, "http://link1.com"); + UpdatePartnerInfoServiceRequestDto requestDto = new UpdatePartnerInfoServiceRequestDto(1L, "UpdatedName", true, "http://updated-link.com"); + MockMultipartFile mockFile = new MockMultipartFile("file", "testImage.jpg", "image/jpeg", "Test Image Content".getBytes()); + + when(partnerInformationRepository.findById(1L)).thenReturn(Optional.of(partnerInformation)); + when(s3Adapter.uploadImage(any(MultipartFile.class))) + .thenReturn(ApiResponse.withError(ErrorCode.ERROR_S3_UPDATE_OBJECT)); + + // when + ApiResponse response = partnerInformationService.updatePartnerInfo(requestDto, mockFile); + + // then + assertEquals(ErrorCode.ERROR_S3_UPDATE_OBJECT.getStatus(), response.getStatus()); + assertEquals(ErrorCode.ERROR_S3_UPDATE_OBJECT.getMessage(), response.getMessage()); + } @Test @DisplayName("협력사 텍스트 정보 업데이트 성공 테스트") @@ -346,24 +368,29 @@ void updatePartnerInfoTextFail() { assertEquals(ErrorCode.INVALID_PARTNER_INFORMATION_ID.getMessage(), response.getMessage()); } -// @Test -// @DisplayName("협력사 로고 이미지 업데이트 성공 테스트") -// void updatePartnerLogoImgSuccess() throws IOException { -// // given -// PartnerInformation partnerInformation = new PartnerInformation("Logo1", "Partner1", true, "http://link1.com"); -// MockMultipartFile mockFile = new MockMultipartFile("file", "newTestImage.jpg", "image/jpeg", "New Test Image Content".getBytes()); -// -// when(partnerInformationRepository.findById(1L)).thenReturn(Optional.of(partnerInformation)); -// when(s3Adapter.uploadFile(any(MultipartFile.class))) -// .thenReturn(ApiResponse.ok("S3에 이미지 업로드 성공", "http://example.com/newTestImage.jpg")); -// when(partnerInformationRepository.save(any(PartnerInformation.class))).thenReturn(partnerInformation); -// -// // when -// ApiResponse response = partnerInformationService.updatePartnerLogoImg(1L, mockFile); -// -// // then -// assertEquals("http://example.com/newTestImage.jpg", response.getData().getLogoImageUrl()); -// } + @Test + @DisplayName("협력사 로고 이미지 업데이트 성공 테스트") + void updatePartnerLogoImgSuccess() throws IOException { + // given + PartnerInformation existingPartner = new PartnerInformation("Logo1", "Partner1", true, "http://link1.com"); + String newLogoImgUrl = "http://example.com/new-logo.png"; + + when(partnerInformationRepository.findById(1L)).thenReturn(Optional.of(existingPartner)); + when(s3Adapter.uploadImage(any(MultipartFile.class))) + .thenReturn(ApiResponse.ok("S3 버킷에 이미지 업로드를 성공하였습니다.", newLogoImgUrl)); + when(partnerInformationRepository.save(any(PartnerInformation.class))) + .thenAnswer(invocation -> invocation.getArgument(0)); + + // when + ApiResponse response = partnerInformationService.updatePartnerLogoImg(1L, mockFile); + + // then + assertEquals("협력사 로고 이미지를 성공적으로 수정했습니다.", response.getMessage()); + PartnerInformation updatedPartner = response.getData(); + assertEquals(newLogoImgUrl, updatedPartner.getLogoImageUrl()); + verify(partnerInformationRepository, times(1)).save(existingPartner); + } + @Test @DisplayName("협력사 로고 이미지 업데이트 실패 테스트 - 유효하지 않은 협력사 ID") @@ -379,37 +406,45 @@ void updatePartnerLogoImgInvalidPartnerId() { assertEquals(ErrorCode.INVALID_PARTNER_INFORMATION_ID.getMessage(), response.getMessage()); } -// @Test -// @DisplayName("협력사 로고 이미지 업데이트 실패 테스트 - S3 이미지 업데이트 실패") -// void updatePartnerLogoImgS3UpdateFail() throws IOException { -// // given -// PartnerInformation partnerInformation = new PartnerInformation("Logo1", "Partner1", true, "http://link1.com"); -// when(partnerInformationRepository.findById(1L)).thenReturn(Optional.of(partnerInformation)); -// when(s3Adapter.uploadFile(any(MultipartFile.class))) -// .thenReturn(ApiResponse.withError(ErrorCode.ERROR_S3_UPDATE_OBJECT)); -// -// // when -// ApiResponse response = partnerInformationService.updatePartnerLogoImg(1L, mockFile); -// -// // then -// assertEquals(ErrorCode.ERROR_S3_UPDATE_OBJECT.getStatus(), response.getStatus()); -// assertEquals(ErrorCode.ERROR_S3_UPDATE_OBJECT.getMessage(), response.getMessage()); -// } - -// @Test -// @DisplayName("협력사 정보 삭제 성공 테스트") -// void deletePartnerInfoSuccess() { -// // given -// PartnerInformation partnerInformation = new PartnerInformation("Logo1", "Partner1", true, "http://link1.com"); -// when(partnerInformationRepository.findById(1L)).thenReturn(Optional.of(partnerInformation)); -// when(s3Adapter.deleteFile(anyString())).thenReturn(ApiResponse.ok("S3에서 이미지 삭제 성공")); -// -// // when -// ApiResponse response = partnerInformationService.deletePartnerInfo(1L); -// -// // then -// assertEquals("협력사 정보를 성공적으로 삭제하였습니다.", response.getMessage()); -// } + @Test + @DisplayName("협력사 로고 이미지 업데이트 실패 테스트 - S3 이미지 업데이트 실패") + void updatePartnerLogoImgS3UpdateFail() throws IOException { + // given + PartnerInformation partnerInformation = new PartnerInformation("Logo1", "Partner1", true, "http://link1.com"); + when(partnerInformationRepository.findById(1L)).thenReturn(Optional.of(partnerInformation)); + when(s3Adapter.uploadImage(any(MultipartFile.class))) + .thenReturn(ApiResponse.withError(ErrorCode.ERROR_S3_UPDATE_OBJECT)); + + // when + ApiResponse response = partnerInformationService.updatePartnerLogoImg(1L, mockFile); + + // then + assertEquals(ErrorCode.ERROR_S3_UPDATE_OBJECT.getStatus(), response.getStatus()); + assertEquals(ErrorCode.ERROR_S3_UPDATE_OBJECT.getMessage(), response.getMessage()); + } + + @Test + @DisplayName("협력사 정보 삭제 성공 테스트") + void deletePartnerInfoSuccess() { + // given + Long validPartnerId = 1L; + String logoImageUrl = "https://example-bucket.s3.amazonaws.com/path/to/logo.png"; + PartnerInformation mockPartnerInformation = PartnerInformation.builder() + .logoImageUrl(logoImageUrl) + .build(); + + when(partnerInformationRepository.findById(validPartnerId)) + .thenReturn(Optional.of(mockPartnerInformation)); + when(s3Adapter.deleteFile(any(String.class))) + .thenReturn(ApiResponse.ok("협력사 정보를 성공적으로 삭제하였습니다.")); + + // when + ApiResponse response = partnerInformationService.deletePartnerInfo(validPartnerId); + + // then + assertEquals("협력사 정보를 성공적으로 삭제하였습니다.", response.getMessage()); + verify(partnerInformationRepository, times(1)).delete(mockPartnerInformation); + } @Test @DisplayName("협력사 정보 삭제 실패 테스트 - 유효하지 않은 협력사 ID") @@ -424,4 +459,28 @@ void deletePartnerInfoInvalidPartnerId() { assertEquals(ErrorCode.INVALID_PARTNER_INFORMATION_ID.getStatus(), response.getStatus()); assertEquals(ErrorCode.INVALID_PARTNER_INFORMATION_ID.getMessage(), response.getMessage()); } + + @Test + @DisplayName("협력사 정보 삭제 실패 테스트 - S3 5xx 에러") + void deletePartnerInfoSuccess_S3_5xx() { + // given + Long validPartnerId = 1L; + String logoImageUrl = "https://example-bucket.s3.amazonaws.com/path/to/logo.png"; + PartnerInformation mockPartnerInformation = PartnerInformation.builder() + .logoImageUrl(logoImageUrl) + .build(); + + when(partnerInformationRepository.findById(validPartnerId)) + .thenReturn(Optional.of(mockPartnerInformation)); + when(s3Adapter.deleteFile(any(String.class))) + .thenReturn(ApiResponse.withError(ErrorCode.ERROR_S3_DELETE_OBJECT)); + + // when + ApiResponse response = partnerInformationService.deletePartnerInfo(validPartnerId); + + // then + assertEquals(ErrorCode.ERROR_S3_DELETE_OBJECT.getStatus(), response.getStatus()); + assertEquals(ErrorCode.ERROR_S3_DELETE_OBJECT.getMessage(), response.getMessage()); + verify(partnerInformationRepository, times(0)).delete(mockPartnerInformation); + } } \ No newline at end of file diff --git a/src/test/java/studio/studioeye/domain/project/application/ProjectServiceTest.java b/src/test/java/studio/studioeye/domain/project/application/ProjectServiceTest.java index 240061f5..a64f2eb1 100644 --- a/src/test/java/studio/studioeye/domain/project/application/ProjectServiceTest.java +++ b/src/test/java/studio/studioeye/domain/project/application/ProjectServiceTest.java @@ -1,334 +1,1301 @@ -//package studio.studioeye.domain.project.application; -// -//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.http.HttpStatus; -//import org.springframework.mock.web.MockMultipartFile; -//import org.springframework.web.multipart.MultipartFile; -//import studio.studioeye.domain.project.application.ProjectService; -//import studio.studioeye.domain.project.dao.ProjectRepository; -//import studio.studioeye.domain.project.domain.Project; -//import studio.studioeye.domain.project.dto.request.CreateProjectServiceRequestDto; -//import studio.studioeye.domain.project.dto.request.UpdatePostingStatusDto; -//import studio.studioeye.domain.project.dto.request.UpdateProjectServiceRequestDto; -//import studio.studioeye.domain.project.dto.request.UpdateProjectTypeDto; -//import studio.studioeye.global.common.response.ApiResponse; -//import studio.studioeye.global.exception.error.ErrorCode; -//import studio.studioeye.infrastructure.s3.S3Adapter; -// -//import java.io.IOException; -//import java.util.ArrayList; -//import java.util.Collections; -//import java.util.List; -//import java.util.Optional; -// -//import static org.junit.jupiter.api.Assertions.*; -//import static org.mockito.ArgumentMatchers.any; -//import static org.mockito.Mockito.*; -// -//@ExtendWith(MockitoExtension.class) -//public class ProjectServiceTest { -// -// @InjectMocks -// private ProjectService projectService; -// -// @Mock -// private ProjectRepository projectRepository; -// -// @Mock -// private S3Adapter s3Adapter; -// -// // Mock MultipartFile 생성 -// MockMultipartFile mockFile = new MockMultipartFile( -// "file", -// "testImage.jpg", -// "image/jpeg", -// "Test Image Content".getBytes() -// ); -// -//// @Test -//// @DisplayName("Project 생성 성공") -//// public void createProjectSuccess() throws IOException { -//// // given -//// CreateProjectServiceRequestDto requestDto = new CreateProjectServiceRequestDto( -//// "Test Department", -//// "Entertainment", -//// "Test Name", -//// "Test Client", -//// "2024-01-01", -//// "Test Link", -//// "Test Overview", -//// "main", -//// true -//// ); -//// -//// // Mock S3 upload 동작 설정 -//// when(s3Adapter.uploadFile(any(MultipartFile.class))) -//// .thenReturn(ApiResponse.ok("프로젝트를 성공적으로 등록하였습니다.", "http://example.com/testImage.jpg")); -//// -//// // List로 변환 -//// List projectImages = List.of(mockFile); -//// -//// // when -//// ApiResponse response = projectService.createProject(requestDto, mockFile, projectImages); -//// -//// // then -//// assertNotNull(response); -//// assertEquals(HttpStatus.OK, response.getStatus()); -//// assertEquals("프로젝트를 성공적으로 등록하였습니다.", response.getMessage()); -//// assertNotNull(response.getData()); -//// } -// -//// @Test -//// @DisplayName("Project 생성 실패 - 이미지 업로드 실패") -//// public void createProjectFail() throws IOException { -//// // given -//// CreateProjectServiceRequestDto requestDto = new CreateProjectServiceRequestDto( -//// "Test Department", -//// "Entertainment", -//// "Test Name", -//// "Test Client", -//// "2024-01-01", -//// "Test Link", -//// "Test Overview", -//// "main", -//// true -//// ); -//// -//// // stub - S3 upload 실패 -//// when(s3Adapter.uploadFile(any(MultipartFile.class))) -//// .thenReturn(null); // null을 반환하여 예외를 유발하도록 수정 -//// -//// // when -//// List projectImages = List.of(mockFile); -//// ApiResponse response = projectService.createProject(requestDto, mockFile, projectImages); -//// -//// // then -//// assertNotNull(response); -//// assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatus()); // 적절한 상태 코드 수정 -//// assertEquals("이미지 업로드 중 오류가 발생했습니다.", response.getMessage()); // 예외 메시지 수정 -//// } -// -//// @Test -//// @DisplayName("Project 수정 성공 테스트") -//// void updateProjectSuccess() throws IOException { -//// // given -//// Long id = 1L; -//// UpdateProjectServiceRequestDto requestDto = new UpdateProjectServiceRequestDto( -//// id, "Updated Department", "Entertainment", "Updated Name", "Updated Client", "2024-01-02", "Updated Link", "Updated Overview", "main", true); -//// -//// Project savedProject = new Project("Test Department", "Entertainment", "Test Name", "Test Client", -//// "2024-01-01", "Test Link", "Test Overview", mockFile.getName(), null, 0, 0, "main", true); -//// -//// // Mock existing images as MultipartFile -//// List existingImages = List.of(mockFile); -//// -//// // stub -//// when(projectRepository.findById(requestDto.projectId())).thenReturn(Optional.of(savedProject)); -//// when(s3Adapter.deleteFile(savedProject.getMainImg())).thenReturn(ApiResponse.ok("S3에서 파일 삭제 성공")); -//// when(s3Adapter.uploadFile(any(MultipartFile.class))) -//// .thenReturn(ApiResponse.ok("S3에 이미지 업로드 성공", "Updated Test ImageUrl")); -//// when(projectRepository.save(any(Project.class))).thenReturn(savedProject); -//// -//// // when -//// ApiResponse response = projectService.updateProject(requestDto, mockFile, existingImages); -//// -//// // then -//// assertNotNull(response); -//// assertEquals(HttpStatus.OK, response.getStatus()); -//// assertEquals("프로젝트를 성공적으로 수정했습니다.", response.getMessage()); -//// assertEquals("Updated Test ImageUrl", savedProject.getMainImg()); -//// } -// -// @Test -// @DisplayName("Project 수정 실패 - 유효하지 않은 ID") -// void updateProjectFail() throws IOException { -// // given -// Long id = 1L; -// UpdateProjectServiceRequestDto requestDto = new UpdateProjectServiceRequestDto( -// id, "Updated Department", "Entertainment", "Updated Name", "Updated Client", "2024-01-02", "Updated Link", "Updated Overview", "main", true); -// -// // stub -// when(projectRepository.findById(requestDto.projectId())).thenReturn(Optional.empty()); -// -// // when -// ApiResponse response = projectService.updateProject(requestDto, mockFile, List.of(mockFile)); -// -// // then -// assertNotNull(response); -// assertEquals(HttpStatus.BAD_REQUEST, response.getStatus()); -// assertEquals("유효하지 않은 project 식별자입니다.", response.getMessage()); -// } -// -// -// @Test -// @DisplayName("프로젝트 게시 상태 수정 성공") -// void UpdatePostingStatusSuccess() { -// Long projectId = 1L; -// UpdatePostingStatusDto dto = new UpdatePostingStatusDto(projectId, true); -// Project project = new Project("Test Department", "Entertainment", "Test Name", "Test Client", -// "2024-01-01", "Test Link", "Test Overview", mockFile.getName(), null, 0, 0, "main", true); -// -// when(projectRepository.findById(projectId)).thenReturn(Optional.of(project)); -// -// ApiResponse response = projectService.updatePostingStatus(dto); -// -// assertEquals("프로젝트 게시 여부를 성공적으로 변경하였습니다.", response.getMessage()); -// assertTrue(project.getIsPosted()); // 게시 상태가 true로 변경되었는지 확인 -// } -// -// @Test -// @DisplayName("프로젝트 게시 상태 수정 실패 - 유효하지 않은 ID") -// void UpdatePostingStatusFail() { -// UpdatePostingStatusDto dto = new UpdatePostingStatusDto(999L, true); // 유효하지 않은 ID -// -// when(projectRepository.findById(dto.projectId())).thenReturn(Optional.empty()); -// -// ApiResponse response = projectService.updatePostingStatus(dto); -// -// assertEquals(ErrorCode.INVALID_PROJECT_ID.getStatus(), response.getStatus()); -// } -// -//// @Test -//// @DisplayName("프로젝트 타입 수정 성공") -//// void UpdateProjectTypeSuccess() { -//// Long projectId = 1L; -//// String newType = "main"; // 변경할 타입 -//// UpdateProjectTypeDto dto = new UpdateProjectTypeDto(projectId, newType); -//// Project project = new Project("Test Department", "Entertainment", "Test Name", "Test Client", -//// "2024-01-01", "Test Link", "Test Overview", mockFile.getName(), null, 0, 0, "main", true); -//// -//// when(projectRepository.findById(projectId)).thenReturn(Optional.of(project)); -//// when(projectRepository.findByProjectType(newType)).thenReturn(new ArrayList<>()); -//// -//// ApiResponse response = projectService.updateProjectType(dto); -//// -//// assertEquals("프로젝트 타입을 성공적으로 변경하였습니다.", response.getMessage()); -//// assertEquals(newType, project.getProjectType()); // 타입이 변경되었는지 확인 -//// } -// -// @Test -// @DisplayName("프로젝트 타입 수정 실패 - 유효하지 않은 ID") -// void UpdateProjectTypeFail() { -// UpdateProjectTypeDto dto = new UpdateProjectTypeDto(999L, "top"); // 유효하지 않은 ID -// -// when(projectRepository.findById(dto.projectId())).thenReturn(Optional.empty()); -// -// ApiResponse response = projectService.updateProjectType(dto); -// -// assertEquals(ErrorCode.INVALID_PROJECT_ID.getStatus(), response.getStatus()); -// } -// -// @Test -// @DisplayName("프로젝트 삭제 성공") -// void DeleteProjectSuccess() { -// Long projectId = 1L; -// Project project = new Project("Test Department", "Entertainment", "Test Name", "Test Client", -// "2024-01-01", "Test Link", "Test Overview", mockFile.getName(), null, 0, 0, "main", true); -// -// when(projectRepository.findById(projectId)).thenReturn(Optional.of(project)); -// -// ApiResponse response = projectService.deleteProject(projectId); -// -// assertEquals("프로젝트를 성공적으로 삭제했습니다.", response.getMessage()); -// verify(projectRepository).delete(project); -// } -// -// @Test -// @DisplayName("프로젝트 삭제 실패 - 유효하지 않은 ID") -// void DeleteProjectFail() { -// Long projectId = 999L; // 유효하지 않은 ID -// -// when(projectRepository.findById(projectId)).thenReturn(Optional.empty()); -// -// ApiResponse response = projectService.deleteProject(projectId); -// -// assertEquals(ErrorCode.INVALID_PROJECT_ID.getStatus(), response.getStatus()); -// } -// -// @Test -// @DisplayName("프로젝트 전체 조회 성공") -// void RetrieveAllArtworkProjectSuccess() { -// List projects = new ArrayList<>(); -// projects.add(new Project("Test Department", "Entertainment", "Test Name", "Test Client", -// "2024-01-01", "Test Link", "Test Overview", mockFile.getName(), null, 0, 0, "main", true)); -// -// when(projectRepository.findAllWithImagesAndOrderBySequenceAsc()).thenReturn(projects); -// -// ApiResponse> response = projectService.retrieveAllArtworkProject(); -// -// assertEquals("프로젝트 목록을 성공적으로 조회했습니다.", response.getMessage()); -// assertEquals(projects, response.getData()); // 프로젝트 목록이 반환되었는지 확인 -// } -// -// @Test -// @DisplayName("프로젝트 전체 조회 실패 - 프로젝트가 없는 경우") -// void RetrieveAllArtworkProjectFail() { -// when(projectRepository.findAllWithImagesAndOrderBySequenceAsc()).thenReturn(new ArrayList<>()); -// -// ApiResponse> response = projectService.retrieveAllArtworkProject(); -// -// assertEquals("프로젝트가 존재하지 않습니다.", response.getMessage()); -// } -// -// @Test -// @DisplayName("메인 프로젝트 전체 조회 성공") -// void RetrieveAllMainProjectSuccess() { -// List projects = new ArrayList<>(); -// projects.add(new Project("Test Department", "Entertainment", "Test Name", "Test Client", -// "2024-01-01", "Test Link", "Test Overview", mockFile.getName(), null, 0, 0, "main", true)); -// List topProjects = new ArrayList<>(); -// topProjects.add(new Project("Test Department", "Entertainment", "Test Name", "Test Client", -// "2024-01-01", "Test Link", "Test Overview", mockFile.getName(), null, 0, 0, "main", true)); -// -// when(projectRepository.findAllWithImagesAndOrderByMainSequenceAsc()).thenReturn(projects); -// when(projectRepository.findByProjectType("top")).thenReturn(topProjects); -// -// ApiResponse> response = projectService.retrieveAllMainProject(); -// -// assertEquals("프로젝트 목록을 성공적으로 조회했습니다.", response.getMessage()); -// assertEquals(1 + projects.size(), response.getData().size()); -// } -// -// @Test -// @DisplayName("메인 프로젝트 전체 조회 실패 - 프로젝트가 없는 경우") -// void RetrieveAllMainProjectFail() { -// when(projectRepository.findAllWithImagesAndOrderByMainSequenceAsc()).thenReturn(new ArrayList<>()); -// -// ApiResponse> response = projectService.retrieveAllMainProject(); -// -// assertEquals("프로젝트가 존재하지 않습니다.", response.getMessage()); -// } -// -// @Test -// @DisplayName("단일 프로젝트 조회 성공") -// void RetrieveProjectSuccess() { -// Long projectId = 1L; -// Project project = new Project("Test Department", "Entertainment", "Test Name", "Test Client", -// "2024-01-01", "Test Link", "Test Overview", mockFile.getName(), null, 0, 0, "main", true); -// -// when(projectRepository.findById(projectId)).thenReturn(Optional.of(project)); -// -// ApiResponse response = projectService.retrieveProject(projectId); -// -// assertEquals("프로젝트를 성공적으로 조회했습니다.", response.getMessage()); -// assertEquals(project, response.getData()); -// } -// -// @Test -// @DisplayName("단일 프로젝트 조회 실패 - 유효하지 않은 ID") -// void RetrieveProjectFail() { -// Long projectId = 999L; // 유효하지 않은 ID -// -// when(projectRepository.findById(projectId)).thenReturn(Optional.empty()); -// -// ApiResponse response = projectService.retrieveProject(projectId); -// -// assertEquals(ErrorCode.INVALID_PROJECT_ID.getStatus(), response.getStatus()); -// } -// -//} +package studio.studioeye.domain.project.application; + +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.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +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.HttpStatus; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.web.multipart.MultipartFile; +import studio.studioeye.domain.project.dao.ProjectRepository; +import studio.studioeye.domain.project.domain.Project; +import studio.studioeye.domain.project.domain.ProjectImage; +import studio.studioeye.domain.project.dto.request.*; +import studio.studioeye.domain.recruitment.dao.RecruitmentTitle; +import studio.studioeye.domain.recruitment.domain.Status; +import studio.studioeye.global.common.response.ApiResponse; +import studio.studioeye.global.exception.error.ErrorCode; +import studio.studioeye.infrastructure.s3.S3Adapter; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +public class ProjectServiceTest { + + @InjectMocks + private ProjectService projectService; + + @Mock + private ProjectRepository projectRepository; + + @Mock + private S3Adapter s3Adapter; + + // Mock MultipartFile 생성 + MockMultipartFile mockFile = new MockMultipartFile( + "file", + "testImage.jpg", + "image/jpeg", + "Test Image Content".getBytes() + ); + + @Test + @DisplayName("Project 생성 성공 테스트_mainType인 경우") + public void createProjectSuccess_mainType() throws IOException { + // given + CreateProjectServiceRequestDto requestDto = new CreateProjectServiceRequestDto( + "Test Department", + "Entertainment", + "Test Name", + "Test Client", + "2024-01-01", + "Test Link", + "Test Overview", + "main", + true + ); + + // List로 변환 + List projectImages = List.of(mockFile); + + Project mockProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .build(); + + // stub + // Mock S3 upload 동작 설정 + when(s3Adapter.uploadFile(any(MultipartFile.class))) + .thenReturn(ApiResponse.ok("프로젝트를 성공적으로 등록하였습니다.", "http://example.com/testImage.jpg")); + when(projectRepository.save(any(Project.class))).thenReturn(mockProject); + + // when + ApiResponse response = projectService.createProject(requestDto, mockFile, mockFile, projectImages); + + // then + assertNotNull(response); + assertEquals(HttpStatus.OK, response.getStatus()); + assertNotNull(response.getData()); + assertEquals("프로젝트를 성공적으로 등록하였습니다.", response.getMessage()); + Mockito.verify(projectRepository, times(1)).save(any(Project.class)); + } + + @Test + @DisplayName("Project 생성 성공 테스트_topType인 경우") + public void createProjectSuccess_topType() throws IOException { + // given + CreateProjectServiceRequestDto requestDto = new CreateProjectServiceRequestDto( + "Test Department", + "Entertainment", + "Test Name", + "Test Client", + "2024-01-01", + "Test Link", + "Test Overview", + "top", + true + ); + + // List로 변환 + List projectImages = List.of(mockFile); + + Project mockProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("top") + .build(); + + // stub + // Mock S3 upload 동작 설정 + when(s3Adapter.uploadFile(any(MultipartFile.class))) + .thenReturn(ApiResponse.ok("프로젝트를 성공적으로 등록하였습니다.", "http://example.com/testImage.jpg")); + when(projectRepository.save(any(Project.class))).thenReturn(mockProject); + + // when + ApiResponse response = projectService.createProject(requestDto, mockFile, mockFile, projectImages); + + // then + assertNotNull(response); + assertEquals(HttpStatus.OK, response.getStatus()); + assertNotNull(response.getData()); + assertEquals("프로젝트를 성공적으로 등록하였습니다.", response.getMessage()); + Mockito.verify(projectRepository, times(1)).save(any(Project.class)); + } + + @Test + @DisplayName("Project 생성 성공 테스트_othersType인 경우") + public void createProjectSuccess_othersType() throws IOException { + // given + CreateProjectServiceRequestDto requestDto = new CreateProjectServiceRequestDto( + "Test Department", + "Entertainment", + "Test Name", + "Test Client", + "2024-01-01", + "Test Link", + "Test Overview", + "others", + true + ); + + // List로 변환 + List projectImages = List.of(mockFile); + + Project mockProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("others") + .build(); + + // stub + // Mock S3 upload 동작 설정 + when(s3Adapter.uploadFile(any(MultipartFile.class))) + .thenReturn(ApiResponse.ok("프로젝트를 성공적으로 등록하였습니다.", "http://example.com/testImage.jpg")); + when(projectRepository.save(any(Project.class))).thenReturn(mockProject); + + // when + ApiResponse response = projectService.createProject(requestDto, mockFile, mockFile, projectImages); + + // then + assertNotNull(response); + assertEquals(HttpStatus.OK, response.getStatus()); + assertNotNull(response.getData()); + assertEquals("프로젝트를 성공적으로 등록하였습니다.", response.getMessage()); + Mockito.verify(projectRepository, times(1)).save(any(Project.class)); + } + + @Test + @DisplayName("Project 생성 실패 테스트 - 이미지 업로드 실패") + public void createProjectFail() throws IOException { + // given + CreateProjectServiceRequestDto requestDto = new CreateProjectServiceRequestDto( + "Test Department", + "Entertainment", + "Test Name", + "Test Client", + "2024-01-01", + "Test Link", + "Test Overview", + "main", + true + ); + + // stub - S3 upload 실패 + when(s3Adapter.uploadFile(any(MultipartFile.class))).thenReturn(ApiResponse.withError(ErrorCode.ERROR_S3_UPDATE_OBJECT)); + + // when + List projectImages = List.of(mockFile); + ApiResponse response = projectService.createProject(requestDto, mockFile, mockFile, projectImages); + + // then + assertNotNull(response); + assertEquals(ErrorCode.ERROR_S3_UPDATE_OBJECT.getStatus(), response.getStatus()); // 적절한 상태 코드 수정 + assertEquals(ErrorCode.ERROR_S3_UPDATE_OBJECT.getMessage(), response.getMessage()); // 예외 메시지 수정 + Mockito.verify(projectRepository, never()).save(any(Project.class)); + } + + @Test + @DisplayName("Project 생성 실패 테스트 - 유효하지 않은 projectType인 경우") + public void createProjectFail_invalidProjectType() throws IOException { + // given + CreateProjectServiceRequestDto requestDto = new CreateProjectServiceRequestDto( + "Test Department", + "Entertainment", + "Test Name", + "Test Client", + "2024-01-01", + "Test Link", + "Test Overview", + "invalidType", + true + ); + + // stub - S3 upload 실패 + when(s3Adapter.uploadFile(any(MultipartFile.class))) + .thenReturn(ApiResponse.ok("프로젝트를 성공적으로 등록하였습니다.", "http://example.com/testImage.jpg")); + + // when + List projectImages = List.of(mockFile); + ApiResponse response = projectService.createProject(requestDto, mockFile, mockFile, projectImages); + + // then + assertNotNull(response); + assertEquals(ErrorCode.INVALID_PROJECT_TYPE.getStatus(), response.getStatus()); // 적절한 상태 코드 수정 + assertEquals(ErrorCode.INVALID_PROJECT_TYPE.getMessage(), response.getMessage()); // 예외 메시지 수정 + Mockito.verify(projectRepository, never()).save(any(Project.class)); + } + + @Test + @DisplayName("Project 생성 실패 테스트 - TOP 프로젝트가 이미 존재하는 경우") + public void createProjectFail_alreadyExistedTop() throws IOException { + // given + CreateProjectServiceRequestDto requestDto = new CreateProjectServiceRequestDto( + "Test Department", + "Entertainment", + "Test Name", + "Test Client", + "2024-01-01", + "Test Link", + "Test Overview", + "top", + true + ); + + Project mockProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .build(); + + // stub - S3 upload 실패 + when(s3Adapter.uploadFile(any(MultipartFile.class))) + .thenReturn(ApiResponse.ok("프로젝트를 성공적으로 등록하였습니다.", "http://example.com/testImage.jpg")); + when(projectRepository.findByProjectType(requestDto.projectType())).thenReturn(List.of(mockProject)); + + // when + List projectImages = List.of(mockFile); + ApiResponse response = projectService.createProject(requestDto, mockFile, mockFile, projectImages); + + // then + assertNotNull(response); + assertEquals(ErrorCode.TOP_PROJECT_ALREADY_EXISTS.getStatus(), response.getStatus()); // 적절한 상태 코드 수정 + assertEquals(ErrorCode.TOP_PROJECT_ALREADY_EXISTS.getMessage(), response.getMessage()); // 예외 메시지 수정 + Mockito.verify(projectRepository, never()).save(any(Project.class)); + } + + @Test + @DisplayName("Project 생성 실패 테스트 - isPosted가 false인 TOP 프로젝트의 경우") + public void createProjectFail_isPostedFalseTop() throws IOException { + // given + CreateProjectServiceRequestDto requestDto = new CreateProjectServiceRequestDto( + "Test Department", + "Entertainment", + "Test Name", + "Test Client", + "2024-01-01", + "Test Link", + "Test Overview", + "top", + false + ); + + + // stub - S3 upload 실패 + when(s3Adapter.uploadFile(any(MultipartFile.class))) + .thenReturn(ApiResponse.ok("프로젝트를 성공적으로 등록하였습니다.", "http://example.com/testImage.jpg")); + when(projectRepository.findByProjectType(requestDto.projectType())).thenReturn(List.of()); + + // when + List projectImages = List.of(mockFile); + ApiResponse response = projectService.createProject(requestDto, mockFile, mockFile, projectImages); + + // then + assertNotNull(response); + assertEquals(ErrorCode.PROJECT_TYPE_AND_IS_POSTED_MISMATCH.getStatus(), response.getStatus()); // 적절한 상태 코드 수정 + assertEquals(ErrorCode.PROJECT_TYPE_AND_IS_POSTED_MISMATCH.getMessage(), response.getMessage()); // 예외 메시지 수정 + Mockito.verify(projectRepository, never()).save(any(Project.class)); + } + + @Test + @DisplayName("Project 생성 실패 테스트 - main인 프로젝트가 이미 5개 이상인 경우") + public void createProjectFail_overMainProjectCount() throws IOException { + // given + CreateProjectServiceRequestDto requestDto = new CreateProjectServiceRequestDto( + "Test Department", + "Entertainment", + "Test Name", + "Test Client", + "2024-01-01", + "Test Link", + "Test Overview", + "main", + true + ); + + Project mockProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .build(); + + + // stub - S3 upload 실패 + when(s3Adapter.uploadFile(any(MultipartFile.class))) + .thenReturn(ApiResponse.ok("프로젝트를 성공적으로 등록하였습니다.", "http://example.com/testImage.jpg")); + when(projectRepository.findByProjectType(requestDto.projectType())).thenReturn(List.of(mockProject, mockProject, mockProject, mockProject, mockProject)); + + // when + List projectImages = List.of(mockFile); + ApiResponse response = projectService.createProject(requestDto, mockFile, mockFile, projectImages); + + // then + assertNotNull(response); + assertEquals(ErrorCode.MAIN_PROJECT_LIMIT_EXCEEDED.getStatus(), response.getStatus()); // 적절한 상태 코드 수정 + assertEquals(ErrorCode.MAIN_PROJECT_LIMIT_EXCEEDED.getMessage(), response.getMessage()); // 예외 메시지 수정 + Mockito.verify(projectRepository, never()).save(any(Project.class)); + } + + @Test + @DisplayName("Project 생성 실패 테스트 - main인데 isPosted를 false로 할 경우") + public void createProjectFail_isPostedFalseMain() throws IOException { + // given + CreateProjectServiceRequestDto requestDto = new CreateProjectServiceRequestDto( + "Test Department", + "Entertainment", + "Test Name", + "Test Client", + "2024-01-01", + "Test Link", + "Test Overview", + "main", + false + ); + + Project mockProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .build(); + + + // stub - S3 upload 실패 + when(s3Adapter.uploadFile(any(MultipartFile.class))) + .thenReturn(ApiResponse.ok("프로젝트를 성공적으로 등록하였습니다.", "http://example.com/testImage.jpg")); + when(projectRepository.findByProjectType(requestDto.projectType())).thenReturn(List.of(mockProject, mockProject, mockProject, mockProject)); + + // when + List projectImages = List.of(mockFile); + ApiResponse response = projectService.createProject(requestDto, mockFile, mockFile, projectImages); + + // then + assertNotNull(response); + assertEquals(ErrorCode.PROJECT_TYPE_AND_IS_POSTED_MISMATCH.getStatus(), response.getStatus()); // 적절한 상태 코드 수정 + assertEquals(ErrorCode.PROJECT_TYPE_AND_IS_POSTED_MISMATCH.getMessage(), response.getMessage()); // 예외 메시지 수정 + Mockito.verify(projectRepository, never()).save(any(Project.class)); + } + + @Test + @DisplayName("Project 수정 성공 테스트") + void updateProjectSuccess() throws IOException { + // given + Long id = 1L; + UpdateProjectServiceRequestDto requestDto = new UpdateProjectServiceRequestDto( + id, "Updated Department", "Entertainment", "Updated Name", "Updated Client", "2024-01-02", "Updated Link", "Updated Overview", "main", true); + + // Mock existing images as MultipartFile + List existingImages = List.of(mockFile); + + Project mockProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .build(); + + List mockProjectImages = new ArrayList<>(); + mockProjectImages.add(ProjectImage.builder() + .project(mockProject) + .fileName(mockProject.getName()) + .imageUrlList(mockProject.getMainImg()) + .build()); + + mockProject.setProjectImages(mockProjectImages); + + // stub + when(projectRepository.findById(requestDto.projectId())).thenReturn(Optional.of(mockProject)); + when(s3Adapter.deleteFile(any(String.class))).thenReturn( + ApiResponse.ok("S3 버킷에서 이미지를 성공적으로 삭제하였습니다.", "http://example.com/testImage.jpg")); + when(s3Adapter.uploadFile(any(MultipartFile.class))) + .thenReturn(ApiResponse.ok("S3 버킷에 이미지 업로드를 성공하였습니다.", "Updated Test ImageUrl")); + when(projectRepository.save(any(Project.class))).thenReturn(mockProject); + + // when + ApiResponse response = projectService.updateProject(requestDto, mockFile, mockFile, existingImages); + + // then + assertNotNull(response); + assertEquals(HttpStatus.OK, response.getStatus()); + assertEquals("프로젝트를 성공적으로 수정했습니다.", response.getMessage()); + assertEquals("Updated Test ImageUrl", mockProject.getMainImg()); + Mockito.verify(projectRepository, times(1)).save(any(Project.class)); + } + + @Test + @DisplayName("Project 수정 실패 테스트 - 유효하지 않은 ID") + void updateProjectFail_invalidID() throws IOException { + // given + Long id = 1L; + UpdateProjectServiceRequestDto requestDto = new UpdateProjectServiceRequestDto( + id, "Updated Department", "Entertainment", "Updated Name", "Updated Client", "2024-01-02", "Updated Link", "Updated Overview", "main", true); + + // stub + when(projectRepository.findById(requestDto.projectId())).thenReturn(Optional.empty()); + + // when + ApiResponse response = projectService.updateProject(requestDto, mockFile, mockFile, List.of(mockFile)); + + // then + assertNotNull(response); + assertEquals(ErrorCode.INVALID_PROJECT_ID.getStatus(), response.getStatus()); + assertEquals(ErrorCode.INVALID_PROJECT_ID.getMessage(), response.getMessage()); + Mockito.verify(projectRepository, never()).save(any(Project.class)); + } + + + @Test + @DisplayName("프로젝트 게시 상태 수정 성공 테스트") + void UpdatePostingStatusSuccess() { + Long projectId = 1L; + UpdatePostingStatusDto dto = new UpdatePostingStatusDto(projectId, true); + + Project mockProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .build(); + + when(projectRepository.findById(projectId)).thenReturn(Optional.of(mockProject)); + + ApiResponse response = projectService.updatePostingStatus(dto); + + assertEquals("프로젝트 게시 여부를 성공적으로 변경하였습니다.", response.getMessage()); + assertTrue(mockProject.getIsPosted()); // 게시 상태가 true로 변경되었는지 확인 + } + + @Test + @DisplayName("프로젝트 게시 상태 수정 실패 테스트 - 유효하지 않은 ID") + void UpdatePostingStatusFail_invalidID() { + UpdatePostingStatusDto dto = new UpdatePostingStatusDto(999L, true); // 유효하지 않은 ID + + when(projectRepository.findById(dto.projectId())).thenReturn(Optional.empty()); + + ApiResponse response = projectService.updatePostingStatus(dto); + + assertEquals(ErrorCode.INVALID_PROJECT_ID.getStatus(), response.getStatus()); + } + + @Test + @DisplayName("프로젝트 타입 수정 성공 테스트 - 기존 타입이 top인 경우") + void UpdateProjectTypeSuccess_topType() { + Long projectId = 1L; + String newType = "main"; // 변경할 타입 + UpdateProjectTypeDto dto = new UpdateProjectTypeDto(projectId, newType); + Project mockProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("top") + .build(); + + when(projectRepository.findById(projectId)).thenReturn(Optional.of(mockProject)); + when(projectRepository.findByProjectType(newType)).thenReturn(new ArrayList<>()); + + ApiResponse response = projectService.updateProjectType(dto); + + assertEquals("프로젝트 타입을 성공적으로 변경하였습니다.", response.getMessage()); + assertEquals(newType, mockProject.getProjectType()); // 타입이 변경되었는지 확인 + } + + @Test + @DisplayName("프로젝트 타입 수정 성공 테스트 - 기존 타입이 main인 경우") + void UpdateProjectTypeSuccess_mainType() { + Long projectId = 1L; + String newType = "main"; // 변경할 타입 + UpdateProjectTypeDto dto = new UpdateProjectTypeDto(projectId, newType); + Project mockProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .build(); + + when(projectRepository.findById(projectId)).thenReturn(Optional.of(mockProject)); + + ApiResponse response = projectService.updateProjectType(dto); + + assertEquals("프로젝트 타입을 성공적으로 변경하였습니다.", response.getMessage()); + assertEquals(newType, mockProject.getProjectType()); // 타입이 변경되었는지 확인 + } + + @Test + @DisplayName("프로젝트 타입 수정 성공 테스트 - 기존 타입이 others인 경우") + void UpdateProjectTypeSuccess_otherType() { + Long projectId = 1L; + String newType = "main"; // 변경할 타입 + UpdateProjectTypeDto dto = new UpdateProjectTypeDto(projectId, newType); + Project mockProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("others") + .build(); + + when(projectRepository.findById(projectId)).thenReturn(Optional.of(mockProject)); + when(projectRepository.findByProjectType(newType)).thenReturn(new ArrayList<>()); + + ApiResponse response = projectService.updateProjectType(dto); + + assertEquals("프로젝트 타입을 성공적으로 변경하였습니다.", response.getMessage()); + assertEquals(newType, mockProject.getProjectType()); // 타입이 변경되었는지 확인 + } + + @Test + @DisplayName("프로젝트 타입 수정 실패 테스트 - 유효하지 않은 ID") + void UpdateProjectTypeFail_invalidID() { + UpdateProjectTypeDto dto = new UpdateProjectTypeDto(999L, "top"); // 유효하지 않은 ID + + when(projectRepository.findById(dto.projectId())).thenReturn(Optional.empty()); + + ApiResponse response = projectService.updateProjectType(dto); + + assertEquals(ErrorCode.INVALID_PROJECT_ID.getStatus(), response.getStatus()); + assertEquals(ErrorCode.INVALID_PROJECT_ID.getMessage(), response.getMessage()); + } + + @Test + @DisplayName("프로젝트 타입 수정 실패 테스트 - 유효하지 projectType인 경우") + void UpdateProjectTypeFail_invalidProjectType() { + UpdateProjectTypeDto dto = new UpdateProjectTypeDto(1L, "invalidValue"); + + Project mockProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("other") + .build(); + + when(projectRepository.findById(dto.projectId())).thenReturn(Optional.of(mockProject)); + + ApiResponse response = projectService.updateProjectType(dto); + + assertEquals(ErrorCode.INVALID_PROJECT_TYPE.getStatus(), response.getStatus()); + assertEquals(ErrorCode.INVALID_PROJECT_TYPE.getMessage(), response.getMessage()); + } + + @Test + @DisplayName("프로젝트 타입 수정 실패 테스트 - TOP 프로젝트가 이미 존재하고, 전달된 프로젝트 id가 이미 존재하는 TOP 프로젝트 id와 다른 경우") + void UpdateProjectTypeFail_alreadyExistedTopAndinvalidTopProjectID() { + UpdateProjectTypeDto dto = new UpdateProjectTypeDto(1L, "top"); + + Project newProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("top") + .build(); + // 리플렉션으로 ID 설정 + ReflectionTestUtils.setField(newProject, "id", 1L); + + String newType = "top"; // 변경할 타입 + + Project mockProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("top") + .build(); + + // 리플렉션으로 ID 설정 + ReflectionTestUtils.setField(mockProject, "id", 500L); + + when(projectRepository.findById(dto.projectId())).thenReturn(Optional.of(newProject)); + when(projectRepository.findByProjectType(newType)).thenReturn(List.of(mockProject)); + + ApiResponse response = projectService.updateProjectType(dto); + + assertEquals(ErrorCode.TOP_PROJECT_ALREADY_EXISTS.getStatus(), response.getStatus()); + assertEquals(ErrorCode.TOP_PROJECT_ALREADY_EXISTS.getMessage(), response.getMessage()); + } + + @Test + @DisplayName("프로젝트 타입 수정 실패 테스트 - main인 프로젝트가 이미 5개 이상인 경우") + void UpdateProjectTypeFail_overMainProjectCount() { + UpdateProjectTypeDto dto = new UpdateProjectTypeDto(1L, "main"); + + Project newProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("top") + .build(); + // 리플렉션으로 ID 설정 +// ReflectionTestUtils.setField(newProject, "id", 1L); + + String newType = "main"; // 변경할 타입 + + Project mockProject = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .build(); + + when(projectRepository.findById(dto.projectId())).thenReturn(Optional.of(newProject)); + when(projectRepository.findByProjectType(newType)).thenReturn(List.of(mockProject, mockProject, mockProject, mockProject, mockProject)); + + ApiResponse response = projectService.updateProjectType(dto); + + assertEquals(ErrorCode.MAIN_PROJECT_LIMIT_EXCEEDED.getStatus(), response.getStatus()); + assertEquals(ErrorCode.MAIN_PROJECT_LIMIT_EXCEEDED.getMessage(), response.getMessage()); + } + + @Test + @DisplayName("프로젝트 삭제 성공 테스트") + void DeleteProjectSuccess() { + Long projectId = 1L; + Project project = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("top") + .build(); + + List mockProjectImages = new ArrayList<>(); + mockProjectImages.add(ProjectImage.builder() + .project(project) + .fileName(project.getName()) + .imageUrlList(project.getMainImg()) + .build()); + + project.setProjectImages(mockProjectImages); + + when(projectRepository.findById(projectId)).thenReturn(Optional.of(project)); + + ApiResponse response = projectService.deleteProject(projectId); + + assertEquals("프로젝트를 성공적으로 삭제했습니다.", response.getMessage()); + Mockito.verify(projectRepository, times(1)).delete(project); + } + + @Test + @DisplayName("프로젝트 삭제 실패 테스트 - 유효하지 않은 ID") + void DeleteProjectFail() { + Long projectId = 999L; // 유효하지 않은 ID + + when(projectRepository.findById(projectId)).thenReturn(Optional.empty()); + + ApiResponse response = projectService.deleteProject(projectId); + + assertEquals(ErrorCode.INVALID_PROJECT_ID.getStatus(), response.getStatus()); + assertEquals(ErrorCode.INVALID_PROJECT_ID.getMessage(), response.getMessage()); + Mockito.verify(projectRepository, never()).delete(any(Project.class)); + } + + @Test + @DisplayName("프로젝트 전체 조회 성공 테스트") + void RetrieveAllArtworkProjectSuccess() { + List projects = new ArrayList<>(); + projects.add(Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("top") + .build()); + + when(projectRepository.findAllWithImagesAndOrderBySequenceAsc()).thenReturn(projects); + + ApiResponse> response = projectService.retrieveAllArtworkProject(); + + assertNotNull(response); + assertNotNull(response.getData()); + assertEquals("프로젝트 목록을 성공적으로 조회했습니다.", response.getMessage()); + assertEquals(projects, response.getData()); // 프로젝트 목록이 반환되었는지 확인 + Mockito.verify(projectRepository, times(1)).findAllWithImagesAndOrderBySequenceAsc(); + } + + @Test + @DisplayName("프로젝트 전체 조회 실패 테스트 - 프로젝트가 없는 경우") + void RetrieveAllArtworkProjectFail() { + when(projectRepository.findAllWithImagesAndOrderBySequenceAsc()).thenReturn(new ArrayList<>()); + + ApiResponse> response = projectService.retrieveAllArtworkProject(); + + assertNotNull(response); + assertNull(response.getData()); + assertEquals("프로젝트가 존재하지 않습니다.", response.getMessage()); + Mockito.verify(projectRepository, times(1)).findAllWithImagesAndOrderBySequenceAsc(); + } + + @Test + @DisplayName("메인 프로젝트 전체 조회 성공 테스트") + void RetrieveAllMainProjectSuccess() { + List projects = new ArrayList<>(); + projects.add(Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .build()); + List topProjects = new ArrayList<>(); + topProjects.add(Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .build()); + + when(projectRepository.findAllWithImagesAndOrderByMainSequenceAsc()).thenReturn(projects); + when(projectRepository.findByProjectType("top")).thenReturn(topProjects); + + ApiResponse> response = projectService.retrieveAllMainProject(); + + assertEquals("프로젝트 목록을 성공적으로 조회했습니다.", response.getMessage()); + assertEquals(1 + projects.size(), response.getData().size()); + } + + @Test + @DisplayName("메인 프로젝트 전체 조회 실패 테스트 - 프로젝트가 없는 경우") + void RetrieveAllMainProjectFail() { + when(projectRepository.findAllWithImagesAndOrderByMainSequenceAsc()).thenReturn(new ArrayList<>()); + + ApiResponse> response = projectService.retrieveAllMainProject(); + + assertEquals("프로젝트가 존재하지 않습니다.", response.getMessage()); + } + + @Test + @DisplayName("단일 프로젝트 조회 성공 테스트") + void RetrieveProjectSuccess() { + Long projectId = 1L; + Project project = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .mainImg("test url") + .mainImgFileName(mockFile.getName()) + .responsiveMainImg("test url") + .responsiveMainImgFileName(mockFile.getName()) + .mainSequence(0) + .sequence(0) + .build(); + + when(projectRepository.findById(projectId)).thenReturn(Optional.of(project)); + + ApiResponse response = projectService.retrieveProject(projectId); + + assertEquals(HttpStatus.OK, response.getStatus()); + assertEquals("프로젝트를 성공적으로 조회했습니다.", response.getMessage()); + assertEquals(project, response.getData()); + Mockito.verify(projectRepository, times(1)).findById(any(Long.class)); + } + + @Test + @DisplayName("단일 프로젝트 조회 실패 테스트 - 유효하지 않은 ID") + void RetrieveProjectFail() { + Long projectId = 999L; // 유효하지 않은 ID + + when(projectRepository.findById(projectId)).thenReturn(Optional.empty()); + + ApiResponse response = projectService.retrieveProject(projectId); + + assertEquals(ErrorCode.INVALID_PROJECT_ID.getStatus(), response.getStatus()); + assertEquals(ErrorCode.INVALID_PROJECT_ID.getMessage(), response.getMessage()); + Mockito.verify(projectRepository, times(1)).findById(any(Long.class)); + } + + @Test + @DisplayName("Artwork Page 프로젝트 순서 변경 성공 테스트") + void changeSequenceProjectSuccess() { + // given + Project project1 = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .mainImg("test url") + .mainImgFileName(mockFile.getName()) + .responsiveMainImg("test url") + .responsiveMainImgFileName(mockFile.getName()) + .mainSequence(1) + .sequence(0) + .build(); + Project project2 = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .mainImg("test url") + .mainImgFileName(mockFile.getName()) + .responsiveMainImg("test url") + .responsiveMainImgFileName(mockFile.getName()) + .mainSequence(1) + .sequence(0) + .build(); + Project project3 = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .mainImg("test url") + .mainImgFileName(mockFile.getName()) + .responsiveMainImg("test url") + .responsiveMainImgFileName(mockFile.getName()) + .mainSequence(1) + .sequence(0) + .build(); + + List changeSequenceProjectReqList = new ArrayList<>(); + ChangeSequenceProjectReq req1 = new ChangeSequenceProjectReq(); + req1.setProjectId(0L); + req1.setSequence(1); + changeSequenceProjectReqList.add(req1); + ChangeSequenceProjectReq req2 = new ChangeSequenceProjectReq(); + req2.setProjectId(1L); + req2.setSequence(2); + changeSequenceProjectReqList.add(req2); + ChangeSequenceProjectReq req3 = new ChangeSequenceProjectReq(); + req3.setProjectId(2L); + req3.setSequence(0); + changeSequenceProjectReqList.add(req3); + + // stub + when(projectRepository.findById(req1.getProjectId())).thenReturn(Optional.of(project1)); + when(projectRepository.findById(req2.getProjectId())).thenReturn(Optional.of(project2)); + when(projectRepository.findById(req3.getProjectId())).thenReturn(Optional.of(project3)); + + // when + ApiResponse response = projectService.changeSequenceProject(changeSequenceProjectReqList); + + // then + assertEquals(HttpStatus.OK, response.getStatus()); + assertEquals("아트워크 페이지에 보여질 프로젝트의 순서를 성공적으로 수정하였습니다.", response.getMessage()); + Mockito.verify(projectRepository, times(3)).findById(any(Long.class)); + } + + @Test + @DisplayName("Artwork Page 프로젝트 순서 변경 실패 테스트 - 유효하지 않은 ID") + void changeSequenceProjectFail_invalidID() { + // given + List changeSequenceProjectReqList = new ArrayList<>(); + ChangeSequenceProjectReq req1 = new ChangeSequenceProjectReq(); + req1.setProjectId(0L); + req1.setSequence(1); + changeSequenceProjectReqList.add(req1); + ChangeSequenceProjectReq req2 = new ChangeSequenceProjectReq(); + req2.setProjectId(1L); + req2.setSequence(2); + changeSequenceProjectReqList.add(req2); + ChangeSequenceProjectReq req3 = new ChangeSequenceProjectReq(); + req3.setProjectId(2L); + req3.setSequence(0); + changeSequenceProjectReqList.add(req3); + + // stub + when(projectRepository.findById(req1.getProjectId())).thenReturn(Optional.empty()); + + // when + ApiResponse response = projectService.changeSequenceProject(changeSequenceProjectReqList); + + // then + assertEquals(ErrorCode.INVALID_PROJECT_ID.getStatus(), response.getStatus()); + assertEquals(ErrorCode.INVALID_PROJECT_ID.getMessage(), response.getMessage()); + } + + @Test + @DisplayName("Main Page 프로젝트 순서 변경 성공 테스트") + void changeMainSequenceProjectSuccess() { + // given + Project project1 = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .mainImg("test url") + .mainImgFileName(mockFile.getName()) + .responsiveMainImg("test url") + .responsiveMainImgFileName(mockFile.getName()) + .mainSequence(1) + .sequence(0) + .build(); + Project project2 = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .mainImg("test url") + .mainImgFileName(mockFile.getName()) + .responsiveMainImg("test url") + .responsiveMainImgFileName(mockFile.getName()) + .mainSequence(1) + .sequence(0) + .build(); + Project project3 = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("main") + .mainImg("test url") + .mainImgFileName(mockFile.getName()) + .responsiveMainImg("test url") + .responsiveMainImgFileName(mockFile.getName()) + .mainSequence(1) + .sequence(0) + .build(); + + List changeMainSequenceProjectReqList = new ArrayList<>(); + ChangeMainSequenceProjectReq req1 = new ChangeMainSequenceProjectReq(); + req1.setProjectId(0L); + req1.setMainSequence(1); + changeMainSequenceProjectReqList.add(req1); + ChangeMainSequenceProjectReq req2 = new ChangeMainSequenceProjectReq(); + req2.setProjectId(1L); + req2.setMainSequence(2); + changeMainSequenceProjectReqList.add(req2); + ChangeMainSequenceProjectReq req3 = new ChangeMainSequenceProjectReq(); + req3.setProjectId(2L); + req3.setMainSequence(0); + changeMainSequenceProjectReqList.add(req3); + + // stub + when(projectRepository.findById(req1.getProjectId())).thenReturn(Optional.of(project1)); + when(projectRepository.findById(req2.getProjectId())).thenReturn(Optional.of(project2)); + when(projectRepository.findById(req3.getProjectId())).thenReturn(Optional.of(project3)); + + // when + ApiResponse response = projectService.changeMainSequenceProject(changeMainSequenceProjectReqList); + + // then + assertEquals(HttpStatus.OK, response.getStatus()); + assertEquals("메인 페이지에 보여질 프로젝트의 순서를 성공적으로 수정하였습니다.", response.getMessage()); + Mockito.verify(projectRepository, times(3)).findById(any(Long.class)); + } + + @Test + @DisplayName("Main Page 프로젝트 순서 변경 실패 테스트 - 유효하지 않은 ID") + void changeMainSequenceProjectFail_invalidID() { + // given + List changeMainSequenceProjectReqList = new ArrayList<>(); + ChangeMainSequenceProjectReq req1 = new ChangeMainSequenceProjectReq(); + req1.setProjectId(0L); + req1.setMainSequence(1); + changeMainSequenceProjectReqList.add(req1); + ChangeMainSequenceProjectReq req2 = new ChangeMainSequenceProjectReq(); + req2.setProjectId(1L); + req2.setMainSequence(2); + changeMainSequenceProjectReqList.add(req2); + ChangeMainSequenceProjectReq req3 = new ChangeMainSequenceProjectReq(); + req3.setProjectId(2L); + req3.setMainSequence(0); + changeMainSequenceProjectReqList.add(req3); + + // stub + when(projectRepository.findById(req1.getProjectId())).thenReturn(Optional.empty()); + + // when + ApiResponse response = projectService.changeMainSequenceProject(changeMainSequenceProjectReqList); + + // then + assertEquals(ErrorCode.INVALID_PROJECT_ID.getStatus(), response.getStatus()); + assertEquals(ErrorCode.INVALID_PROJECT_ID.getMessage(), response.getMessage()); + } + + @Test + @DisplayName("Main Page 프로젝트 순서 변경 실패 테스트 - main type이 아닌 경우") + void changeMainSequenceProjectFail_invalidProjectType() { + // given + Project project1 = Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("others") + .mainImg("test url") + .mainImgFileName(mockFile.getName()) + .responsiveMainImg("test url") + .responsiveMainImgFileName(mockFile.getName()) + .mainSequence(1) + .sequence(0) + .build(); + + List changeMainSequenceProjectReqList = new ArrayList<>(); + ChangeMainSequenceProjectReq req1 = new ChangeMainSequenceProjectReq(); + req1.setProjectId(0L); + req1.setMainSequence(1); + changeMainSequenceProjectReqList.add(req1); + ChangeMainSequenceProjectReq req2 = new ChangeMainSequenceProjectReq(); + req2.setProjectId(1L); + req2.setMainSequence(2); + changeMainSequenceProjectReqList.add(req2); + ChangeMainSequenceProjectReq req3 = new ChangeMainSequenceProjectReq(); + req3.setProjectId(2L); + req3.setMainSequence(0); + changeMainSequenceProjectReqList.add(req3); + + // stub + when(projectRepository.findById(req1.getProjectId())).thenReturn(Optional.of(project1)); + + // when + ApiResponse response = projectService.changeMainSequenceProject(changeMainSequenceProjectReqList); + + // then + assertEquals(ErrorCode.INVALID_PROJECT_ID.getStatus(), response.getStatus()); + assertEquals(ErrorCode.INVALID_PROJECT_ID.getMessage(), response.getMessage()); + } + + @Test + @DisplayName("프로젝트 페이지네이션 조회 성공 테스트") + void retrieveArtworkProjectPageSuccess() { + // given + int page = 0; + int size = 2; + Pageable pageable = PageRequest.of(page, size); + + List projectList = new ArrayList<>(); + projectList.add(Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("others") + .mainImg("test url") + .mainImgFileName(mockFile.getName()) + .responsiveMainImg("test url") + .responsiveMainImgFileName(mockFile.getName()) + .mainSequence(1) + .sequence(0) + .build()); + projectList.add(Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("others") + .mainImg("test url") + .mainImgFileName(mockFile.getName()) + .responsiveMainImg("test url") + .responsiveMainImgFileName(mockFile.getName()) + .mainSequence(1) + .sequence(0) + .build()); + projectList.add(Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("others") + .mainImg("test url") + .mainImgFileName(mockFile.getName()) + .responsiveMainImg("test url") + .responsiveMainImgFileName(mockFile.getName()) + .mainSequence(1) + .sequence(0) + .build()); + projectList.add(Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("others") + .mainImg("test url") + .mainImgFileName(mockFile.getName()) + .responsiveMainImg("test url") + .responsiveMainImgFileName(mockFile.getName()) + .mainSequence(1) + .sequence(0) + .build()); + projectList.add(Project.builder() + .name("Test Name") + .category("Entertainment") + .department("Test Department") + .date("2024-01-01") + .link("Test Link") + .overView("Test Overview") + .isPosted(true) + .projectType("others") + .mainImg("test url") + .mainImgFileName(mockFile.getName()) + .responsiveMainImg("test url") + .responsiveMainImgFileName(mockFile.getName()) + .mainSequence(1) + .sequence(0) + .build()); + + + Page projectPage = new PageImpl<>(projectList, pageable, projectList.size()); + + // stub + when(projectRepository.findAll(pageable)).thenReturn(projectPage); + + // when + Page response = projectService.retrieveArtworkProjectPage(page, size); + + // then + assertNotNull(response); + assertEquals(response.getNumber(), page); + assertEquals(response.getSize(), size); + Mockito.verify(projectRepository, times(1)).findAll(pageable); + } + + @Test + @DisplayName("프로젝트 페이지네이션 조회 실패 테스트 - 잘못된 page인 경우") + void retrieveArtworkProjectPageFail_invalidPage() { + // given + int page = -1; // 잘못된 페이지 번호 + int size = 10; + + // when & then + Exception exception = assertThrows(IllegalArgumentException.class, + () -> projectService.retrieveArtworkProjectPage(page, size)); + assertEquals("Page index must not be less than zero", exception.getMessage()); + } + + @Test + @DisplayName("프로젝트 페이지네이션 조회 실패 테스트 - 잘못된 size인 경우") + void retrieveArtworkProjectPageFail_invalidSize() { + // given + int page = 0; + int size = 0; // 잘못된 크기 + + // when & then + Exception exception = assertThrows(IllegalArgumentException.class, + () -> projectService.retrieveArtworkProjectPage(page, size)); + assertEquals("Page size must not be less than one", exception.getMessage()); + } +} diff --git a/src/test/java/studio/studioeye/domain/request/application/RequestServiceTest.java b/src/test/java/studio/studioeye/domain/request/application/RequestServiceTest.java new file mode 100644 index 00000000..b3b124c4 --- /dev/null +++ b/src/test/java/studio/studioeye/domain/request/application/RequestServiceTest.java @@ -0,0 +1,204 @@ +package studio.studioeye.domain.request.application; + +import studio.studioeye.domain.request.api.RequestController; +import studio.studioeye.domain.request.domain.Request; +import studio.studioeye.domain.request.dto.request.CreateRequestDto; +import studio.studioeye.domain.request.dto.request.UpdateRequestCommentDto; +import studio.studioeye.global.common.response.ApiResponse; +import studio.studioeye.global.exception.error.ErrorCode; +import org.junit.jupiter.api.BeforeEach; +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.http.HttpStatus; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +public class RequestServiceTest { + + @InjectMocks + private RequestController requestController; + @Mock + private RequestService requestService; + private CreateRequestDto createRequestDto; + private UpdateRequestCommentDto updateRequestCommentDto; + private Request request; + + @BeforeEach + void setUp() { + createRequestDto = new CreateRequestDto( + "category", + "projectName", + "clientName", + "organization", + "010-1234-5678", + "test@example.com", + "Developer", + "description" + ); + updateRequestCommentDto = new UpdateRequestCommentDto( + "This is a comment", + studio.studioeye.domain.request.domain.State.APPROVED + ); + request = Request.builder() + .category("category") + .projectName("projectName") + .clientName("clientName") + .organization("organization") + .contact("010-1234-5678") + .email("test@example.com") + .position("Developer") + .description("description") + .build(); + } + @Test + @DisplayName("문의 등록 성공 테스트") + void createRequestSuccess() throws IOException { + // given + List files = Collections.emptyList(); + when(requestService.createRequest(any(), any())).thenReturn(ApiResponse.ok(request)); + // when + ApiResponse response = requestController.createRequest(createRequestDto, files); + // then + assertEquals(HttpStatus.OK, response.getStatus()); + assertNotNull(response.getData()); + verify(requestService, times(1)).createRequest(any(), any()); + } + + @Test + @DisplayName("문의 등록 실패 테스트 - 잘못된 입력") + void createRequestFailDueToInvalidInput() throws IOException { + // given + CreateRequestDto invalidDto = new CreateRequestDto( + "", // 잘못된 category 입력 + "projectName", + "clientName", + "organization", + "010-1234-5678", + "test@example.com", + "Developer", + "description" + ); + when(requestService.createRequest(any(), any())).thenReturn(ApiResponse.withError(ErrorCode.INVALID_INPUT_VALUE)); + // when + ApiResponse response = requestController.createRequest(invalidDto, Collections.emptyList()); + // then + assertEquals(ErrorCode.INVALID_INPUT_VALUE.getStatus(), response.getStatus()); + verify(requestService, times(1)).createRequest(any(), any()); + } + + @Test + @DisplayName("문의 전체 조회 성공 테스트") + void retrieveAllRequestSuccess() { + // given + when(requestService.retrieveAllRequest()).thenReturn(ApiResponse.ok(List.of(request))); + // when + ApiResponse> response = requestController.retrieveAllRequest(); + // then + assertEquals(HttpStatus.OK, response.getStatus()); + assertNotNull(response.getData()); + verify(requestService, times(1)).retrieveAllRequest(); + } + + @Test + @DisplayName("문의 전체 조회 실패 테스트 - 데이터 없음") + void retrieveAllRequestFailDueToNoData() { + // given + when(requestService.retrieveAllRequest()).thenReturn(ApiResponse.ok("문의가 존재하지 않습니다.")); + // when + ApiResponse> response = requestController.retrieveAllRequest(); + // then + assertEquals(HttpStatus.OK, response.getStatus()); + assertNull(response.getData()); + verify(requestService, times(1)).retrieveAllRequest(); + } + + @Test + @DisplayName("문의 상세 조회 성공 테스트") + void retrieveRequestSuccess() { + // given + Long requestId = 1L; + when(requestService.retrieveRequest(requestId)).thenReturn(ApiResponse.ok(request)); + // when + ApiResponse response = requestController.retrieveRequest(requestId); + // then + assertEquals(HttpStatus.OK, response.getStatus()); + assertNotNull(response.getData()); + verify(requestService, times(1)).retrieveRequest(requestId); + } + + @Test + @DisplayName("문의 상세 조회 실패 테스트 - 유효하지 않은 ID") + void retrieveRequestFailDueToInvalidId() { + // given + Long requestId = 1L; + when(requestService.retrieveRequest(requestId)).thenReturn(ApiResponse.withError(ErrorCode.INVALID_REQUEST_ID)); + // when + ApiResponse response = requestController.retrieveRequest(requestId); + // then + assertEquals(ErrorCode.INVALID_REQUEST_ID.getStatus(), response.getStatus()); + verify(requestService, times(1)).retrieveRequest(requestId); + } + + @Test + @DisplayName("기간 및 상태에 따른 문의 수 조회 성공 테스트") + void retrieveRequestCountByCategoryAndStateSuccess() { + // given + String category = "category"; + String state = "APPROVED"; + Integer startYear = 2023; + Integer startMonth = 1; + Integer endYear = 2023; + Integer endMonth = 12; + when(requestService.retrieveRequestCountByCategoryAndState(category, state, startYear, startMonth, endYear, endMonth)) + .thenReturn(ApiResponse.ok(List.of(Map.of("year", 2023, "month", 1, "RequestCount", 10L)))); + // when + ApiResponse>> response = requestController.retrieveStateRequestCountByPeriod( + category, state, startYear, startMonth, endYear, endMonth); + // then + assertEquals(HttpStatus.OK, response.getStatus()); + assertNotNull(response.getData()); + verify(requestService, times(1)).retrieveRequestCountByCategoryAndState(category, state, startYear, startMonth, endYear, endMonth); + } + + // 테스트 실패... +// @Test +// @DisplayName("문의 답변 등록 성공 테스트") +// void updateRequestCommentSuccess() { +// // given +// Long requestId = 1L; +// when(requestService.updateRequestComment(eq(requestId), any())).thenReturn(ApiResponse.ok("답변을 성공적으로 작성했습니다.")); +// // when +// ApiResponse response = requestController.updateRequestComment(requestId, updateRequestCommentDto); +// // then +// assertEquals(HttpStatus.OK, response.getStatus()); +// assertEquals("답변을 성공적으로 작성했습니다.", response.getData()); +// verify(requestService, times(1)).updateRequestComment(eq(requestId), any()); +// } + @Test + @DisplayName("문의 답변 등록 실패 테스트 - 유효하지 않은 ID") + void updateRequestCommentFailDueToInvalidId() { + // given + Long requestId = 1L; + when(requestService.updateRequestComment(requestId, updateRequestCommentDto.toServiceRequest())) + .thenReturn(ApiResponse.withError(ErrorCode.INVALID_REQUEST_ID)); + // when + ApiResponse response = requestController.updateRequestComment(requestId, updateRequestCommentDto); + // then + assertEquals(ErrorCode.INVALID_REQUEST_ID.getStatus(), response.getStatus()); + verify(requestService, times(1)).updateRequestComment(requestId, updateRequestCommentDto.toServiceRequest()); + } +}