diff --git a/src/test/java/com/acquirex/cardacquisition/service/AcquisitionApprovalServiceTest.java b/src/test/java/com/acquirex/cardacquisition/service/AcquisitionApprovalServiceTest.java new file mode 100644 index 0000000..b3197c0 --- /dev/null +++ b/src/test/java/com/acquirex/cardacquisition/service/AcquisitionApprovalServiceTest.java @@ -0,0 +1,138 @@ +package com.acquirex.cardacquisition.service; + +import com.acquirex.cardacquisition.domain.AcquisitionApproval; +import com.acquirex.cardacquisition.domain.AcquisitionApproval.ApprovalStatus; +import com.acquirex.cardacquisition.dto.ApprovalDto.ApprovalRequest; +import com.acquirex.cardacquisition.dto.ApprovalDto.ApprovalResponse; +import com.acquirex.cardacquisition.repository.AcquisitionApprovalRepository; +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 java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class AcquisitionApprovalServiceTest { + + @Mock + private AcquisitionApprovalRepository repository; + + @InjectMocks + private AcquisitionApprovalService service; + + private ApprovalRequest validRequest; + private AcquisitionApproval pendingApproval; + + @BeforeEach + void setUp() { + validRequest = new ApprovalRequest("1234567890123456", "MERCHANT001", new BigDecimal("50000.00")); + + pendingApproval = new AcquisitionApproval(); + pendingApproval.setId(1L); + pendingApproval.setCardNumber("1234567890123456"); + pendingApproval.setMerchantId("MERCHANT001"); + pendingApproval.setAmount(new BigDecimal("50000.00")); + pendingApproval.setStatus(ApprovalStatus.PENDING); + pendingApproval.setCreatedAt(LocalDateTime.now()); + } + + @Test + @DisplayName("매입 승인 요청 생성 성공") + void requestApproval_Success() { + when(repository.save(any(AcquisitionApproval.class))).thenReturn(pendingApproval); + + ApprovalResponse response = service.requestApproval(validRequest); + + assertThat(response).isNotNull(); + assertThat(response.id()).isEqualTo(1L); + assertThat(response.status()).isEqualTo(ApprovalStatus.PENDING); + assertThat(response.cardNumber()).isEqualTo("****-****-****-3456"); + verify(repository, times(1)).save(any(AcquisitionApproval.class)); + } + + @Test + @DisplayName("매입 승인 처리 성공") + void approve_Success() { + AcquisitionApproval approved = new AcquisitionApproval(); + approved.setId(1L); + approved.setCardNumber("1234567890123456"); + approved.setMerchantId("MERCHANT001"); + approved.setAmount(new BigDecimal("50000.00")); + approved.setStatus(ApprovalStatus.APPROVED); + approved.setApprovalCode("APX12345678"); + approved.setCreatedAt(LocalDateTime.now()); + + when(repository.findById(1L)).thenReturn(Optional.of(pendingApproval)); + when(repository.save(any(AcquisitionApproval.class))).thenReturn(approved); + + ApprovalResponse response = service.approve(1L); + + assertThat(response).isNotNull(); + assertThat(response.status()).isEqualTo(ApprovalStatus.APPROVED); + assertThat(response.approvalCode()).isNotNull(); + assertThat(response.approvalCode()).startsWith("APX"); + } + + @Test + @DisplayName("대기 상태가 아닌 요청은 승인 불가") + void approve_NotPending_ThrowsException() { + pendingApproval.setStatus(ApprovalStatus.APPROVED); + when(repository.findById(1L)).thenReturn(Optional.of(pendingApproval)); + + assertThatThrownBy(() -> service.approve(1L)) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("대기 상태의 요청만 승인 가능"); + } + + @Test + @DisplayName("매입 거절 처리 성공") + void reject_Success() { + AcquisitionApproval rejected = new AcquisitionApproval(); + rejected.setId(1L); + rejected.setCardNumber("1234567890123456"); + rejected.setMerchantId("MERCHANT001"); + rejected.setAmount(new BigDecimal("50000.00")); + rejected.setStatus(ApprovalStatus.REJECTED); + rejected.setCreatedAt(LocalDateTime.now()); + + when(repository.findById(1L)).thenReturn(Optional.of(pendingApproval)); + when(repository.save(any(AcquisitionApproval.class))).thenReturn(rejected); + + ApprovalResponse response = service.reject(1L); + + assertThat(response).isNotNull(); + assertThat(response.status()).isEqualTo(ApprovalStatus.REJECTED); + } + + @Test + @DisplayName("존재하지 않는 요청 조회 시 예외 발생") + void getApproval_NotFound_ThrowsException() { + when(repository.findById(999L)).thenReturn(Optional.empty()); + + assertThatThrownBy(() -> service.getApproval(999L)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("찾을 수 없습니다"); + } + + @Test + @DisplayName("대기 중인 승인 목록 조회") + void getPendingApprovals_Success() { + when(repository.findByStatus(ApprovalStatus.PENDING)).thenReturn(List.of(pendingApproval)); + + List responses = service.getPendingApprovals(); + + assertThat(responses).hasSize(1); + assertThat(responses.get(0).status()).isEqualTo(ApprovalStatus.PENDING); + } +} \ No newline at end of file