diff --git a/src/test/java/com/acquirex/approval/CardAcquisitionServiceTest.java b/src/test/java/com/acquirex/approval/CardAcquisitionServiceTest.java new file mode 100644 index 0000000..b0098a5 --- /dev/null +++ b/src/test/java/com/acquirex/approval/CardAcquisitionServiceTest.java @@ -0,0 +1,102 @@ +package com.acquirex.approval; + +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.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.*; + +@ExtendWith(MockitoExtension.class) +class CardAcquisitionServiceTest { + + @Mock + private CardAcquisitionRepository repository; + + @InjectMocks + private CardAcquisitionService service; + + private CardAcquisition testAcquisition; + + @BeforeEach + void setUp() { + testAcquisition = new CardAcquisition("1234567890123456", "MERCH001", new BigDecimal("100000")); + testAcquisition.setId(1L); + } + + @Test + @DisplayName("유효한 정보로 매입 요청을 생성한다") + void shouldCreateAcquisitionWithValidData() { + when(repository.save(any(CardAcquisition.class))).thenReturn(testAcquisition); + CardAcquisition result = service.createAcquisition("1234567890123456", "MERCH001", new BigDecimal("100000")); + assertThat(result).isNotNull(); + assertThat(result.getStatus()).isEqualTo(CardAcquisition.ApprovalStatus.PENDING); + verify(repository, times(1)).save(any(CardAcquisition.class)); + } + + @Test + @DisplayName("금액이 0 이하이면 예외를 발생시킨다") + void shouldThrowExceptionWhenAmountIsZeroOrNegative() { + assertThatThrownBy(() -> service.createAcquisition("1234567890123456", "MERCH001", BigDecimal.ZERO)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("0보다 커야 합니다"); + } + + @Test + @DisplayName("대기 상태의 매입 요청을 승인한다") + void shouldApprovePendingAcquisition() { + when(repository.findById(1L)).thenReturn(Optional.of(testAcquisition)); + when(repository.save(any(CardAcquisition.class))).thenAnswer(i -> i.getArgument(0)); + CardAcquisition result = service.approve(1L, "admin"); + assertThat(result.getStatus()).isEqualTo(CardAcquisition.ApprovalStatus.APPROVED); + assertThat(result.getApprovedBy()).isEqualTo("admin"); + } + + @Test + @DisplayName("이미 승인된 요청은 다시 승인할 수 없다") + void shouldThrowExceptionWhenAlreadyApproved() { + testAcquisition.approve("previous"); + when(repository.findById(1L)).thenReturn(Optional.of(testAcquisition)); + assertThatThrownBy(() -> service.approve(1L, "admin")) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("대기 상태"); + } + + @Test + @DisplayName("대기 상태의 매입 요청을 거절한다") + void shouldRejectPendingAcquisition() { + when(repository.findById(1L)).thenReturn(Optional.of(testAcquisition)); + when(repository.save(any(CardAcquisition.class))).thenAnswer(i -> i.getArgument(0)); + CardAcquisition result = service.reject(1L, "Invalid merchant"); + assertThat(result.getStatus()).isEqualTo(CardAcquisition.ApprovalStatus.REJECTED); + assertThat(result.getRejectionReason()).isEqualTo("Invalid merchant"); + } + + @Test + @DisplayName("존재하지 않는 요청은 예외를 발생시킨다") + void shouldThrowExceptionWhenNotFound() { + when(repository.findById(999L)).thenReturn(Optional.empty()); + assertThatThrownBy(() -> service.approve(999L, "admin")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("찾을 수 없습니다"); + } + + @Test + @DisplayName("상태별 매입 요청을 조회한다") + void shouldFindByStatus() { + when(repository.findByStatus(CardAcquisition.ApprovalStatus.PENDING)) + .thenReturn(List.of(testAcquisition)); + List result = service.findByStatus(CardAcquisition.ApprovalStatus.PENDING); + assertThat(result).hasSize(1); + } +}