diff --git a/src/test/java/com/acquirex/AcquisitionServiceTest.java b/src/test/java/com/acquirex/AcquisitionServiceTest.java new file mode 100644 index 0000000..f52fd7b --- /dev/null +++ b/src/test/java/com/acquirex/AcquisitionServiceTest.java @@ -0,0 +1,160 @@ +package com.acquirex; + +import com.acquirex.domain.Acquisition; +import com.acquirex.domain.AcquisitionStatus; +import com.acquirex.exception.AcquisitionNotFoundException; +import com.acquirex.exception.InvalidAcquisitionStateException; +import com.acquirex.service.AcquisitionRequest; +import com.acquirex.service.AcquisitionResponse; +import com.acquirex.service.AcquisitionService; +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.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +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.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +/** + * AcquisitionService 단위 테스트 - Spring Boot 3 마이그레이션 검증 + */ +@ExtendWith(MockitoExtension.class) +class AcquisitionServiceTest { + + @Mock + private com.acquirex.service.AcquisitionRepository acquisitionRepository; + + private AcquisitionService acquisitionService; + private AcquisitionRequest validRequest; + private Acquisition pendingAcquisition; + + @BeforeEach + void setUp() { + acquisitionService = new AcquisitionService(acquisitionRepository); + validRequest = AcquisitionRequest.builder() + .merchantId("MERCHANT001") + .cardNumber("1234567890123456") + .amount(new BigDecimal("50000.00")) + .build(); + + pendingAcquisition = Acquisition.builder() + .id(1L).merchantId("MERCHANT001").cardNumber("123456****3456") + .amount(new BigDecimal("50000.00")).transactionId("TXN123456789") + .status(AcquisitionStatus.PENDING).createdAt(LocalDateTime.now()).build(); + } + + @Test + @DisplayName("매입 요청 등록 성공 - Spring Boot 3 Jakarta Validation") + void registerAcquisition_Success() { + when(acquisitionRepository.save(any(Acquisition.class))).thenAnswer(invocation -> { + Acquisition saved = invocation.getArgument(0); + saved.setId(1L); + saved.setCreatedAt(LocalDateTime.now()); + return saved; + }); + + AcquisitionResponse response = acquisitionService.registerAcquisition(validRequest); + + assertThat(response).isNotNull(); + assertThat(response.getMerchantId()).isEqualTo("MERCHANT001"); + assertThat(response.getAmount()).isEqualByComparingTo(new BigDecimal("50000.00")); + assertThat(response.getStatus()).isEqualTo(AcquisitionStatus.PENDING); + assertThat(response.getCardNumber()).isEqualTo("123456****3456"); + verify(acquisitionRepository, times(1)).save(any(Acquisition.class)); + } + + @Test + @DisplayName("매입 승인 처리 성공 - Spring Boot 3 @Transactional") + void approveAcquisition_Success() { + when(acquisitionRepository.findByTransactionId("TXN123456789")).thenReturn(Optional.of(pendingAcquisition)); + when(acquisitionRepository.save(any(Acquisition.class))).thenAnswer(invocation -> invocation.getArgument(0)); + + AcquisitionResponse response = acquisitionService.approveAcquisition("TXN123456789"); + + assertThat(response).isNotNull(); + assertThat(response.getStatus()).isEqualTo(AcquisitionStatus.APPROVED); + assertThat(response.getApprovalCode()).isNotNull(); + assertThat(response.getApprovalCode()).hasSize(6); + } + + @Test + @DisplayName("매입 승인 실패 - 매입 정보 없음") + void approveAcquisition_NotFound() { + when(acquisitionRepository.findByTransactionId("INVALID_TXN")).thenReturn(Optional.empty()); + + assertThatThrownBy(() -> acquisitionService.approveAcquisition("INVALID_TXN")) + .isInstanceOf(AcquisitionNotFoundException.class) + .hasMessageContaining("INVALID_TXN"); + } + + @Test + @DisplayName("매입 승인 실패 - 이미 승인된 매입") + void approveAcquisition_AlreadyApproved() { + pendingAcquisition.setStatus(AcquisitionStatus.APPROVED); + when(acquisitionRepository.findByTransactionId("TXN123456789")).thenReturn(Optional.of(pendingAcquisition)); + + assertThatThrownBy(() -> acquisitionService.approveAcquisition("TXN123456789")) + .isInstanceOf(InvalidAcquisitionStateException.class) + .hasMessageContaining("APPROVED"); + } + + @Test + @DisplayName("매입 거절 처리 성공") + void rejectAcquisition_Success() { + when(acquisitionRepository.findByTransactionId("TXN123456789")).thenReturn(Optional.of(pendingAcquisition)); + when(acquisitionRepository.save(any(Acquisition.class))).thenAnswer(invocation -> invocation.getArgument(0)); + + AcquisitionResponse response = acquisitionService.rejectAcquisition("TXN123456789", "한도 초과"); + + assertThat(response).isNotNull(); + assertThat(response.getStatus()).isEqualTo(AcquisitionStatus.REJECTED); + } + + @Test + @DisplayName("매입 정보 조회 성공") + void getAcquisition_Success() { + when(acquisitionRepository.findByTransactionId("TXN123456789")).thenReturn(Optional.of(pendingAcquisition)); + + AcquisitionResponse response = acquisitionService.getAcquisition("TXN123456789"); + + assertThat(response).isNotNull(); + assertThat(response.getTransactionId()).isEqualTo("TXN123456789"); + } + + @Test + @DisplayName("가맹점별 매입 목록 조회 성공") + void getAcquisitionsByMerchant_Success() { + Acquisition acquisition2 = Acquisition.builder() + .id(2L).merchantId("MERCHANT001").cardNumber("987654****3210") + .amount(new BigDecimal("30000.00")).transactionId("TXN987654321") + .status(AcquisitionStatus.PENDING).createdAt(LocalDateTime.now()).build(); + + when(acquisitionRepository.findByMerchantId("MERCHANT001")).thenReturn(Arrays.asList(pendingAcquisition, acquisition2)); + + List responses = acquisitionService.getAcquisitionsByMerchant("MERCHANT001"); + + assertThat(responses).hasSize(2); + assertThat(responses).extracting(AcquisitionResponse::getMerchantId).containsOnly("MERCHANT001"); + } + + @Test + @DisplayName("대기 중인 매입 목록 조회 성공") + void getPendingAcquisitions_Success() { + when(acquisitionRepository.findByStatus(AcquisitionStatus.PENDING)).thenReturn(Arrays.asList(pendingAcquisition)); + + List responses = acquisitionService.getPendingAcquisitions(); + + assertThat(responses).hasSize(1); + assertThat(responses.get(0).getStatus()).isEqualTo(AcquisitionStatus.PENDING); + } +} \ No newline at end of file