Project

[Toss] 잔액사용(2)

sangyunpark 2023. 8. 24. 13:35

Test코드

 

TransactionController Test

@WebMvcTest(TransactionController.class)
class TransactionControllerTest {
    @MockBean
    private TransactionService transactionService;

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    public void successUseBalance() throws Exception {
        //given
        given(transactionService.useBalance(anyLong(), anyString(), anyLong()))
                .willReturn(
                        TransactionDto.builder()
                                .accountNumber("1234567890")
                                .transactionType(USE)
                                .transactionResultType(SUCCESS)
                                .amount(10000L)
                                .balanceSnapshot(10000L)
                                .transactionId("21asfq3qpeu12351cxv")
                                .transactedAt(LocalDateTime.now())
                                .build()
                );
        //when


        //then
        mockMvc.perform(post("/transaction/use")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(
                        new UseBalance.Request(1L,"1234567890",1000L)
                )))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.accountNumber").value("1234567890"))
                .andExpect(jsonPath("$.transactionId").value("21asfq3qpeu12351cxv"))
                .andExpect(jsonPath("$.transactionResult").value("SUCCESS"))
                .andExpect(jsonPath("$.amount").value(10000L))
                .andDo(print());
    }
}

 

TransactionService test 코드

 

성공 case

@ExtendWith(MockitoExtension.class)
class TransactionServiceTest {
    @Mock
    private AccountRepository accountRepository;

    @Mock
    private AccountUserRepository accountUserRepository;

    @Mock
    private TransactionRepository transactionRepository;

    @InjectMocks
    private TransactionService transactionService;

    @Test
    @DisplayName("계좌 사용 성공")
    public void succesUseBalance() throws Exception {
        //given
        AccountUser user = AccountUser.builder()
                .id(12L)
                .name("sy")
                .build();

        Account account = Account.builder()
                        .accountUser(user)
                                .accountStatus(IN_USE)
                                        .accountNumber("1000000012")
                                                .balance(10000L)
                                                        .build();

        given(accountUserRepository.findById(anyLong())).willReturn(Optional.of(user));

        given(accountRepository.findByAccountNumber(anyString())).willReturn(
                Optional.of(account)
        );

        given(transactionRepository.save(any())).willReturn(
                Transaction.builder()
                        .account(account)
                        .transactionType(USE)
                        .balanceSnapshot(9000L)
                        .amount(1000L)
                        .transactionResultType(SUCCESS)
                        .transactedAt(LocalDateTime.now())
                        .build()
        );

        ArgumentCaptor<Transaction> captor = ArgumentCaptor.forClass(Transaction.class);

        //when
        TransactionDto transactionDto = transactionService.useBalance(1L, "1000000012", 200L);

        //then
        verify(transactionRepository, times(1)).save(captor.capture());
        assertEquals(200L, captor.getValue().getAmount());
        assertEquals(9800L,captor.getValue().getBalanceSnapshot());

        assertEquals("1000000012", transactionDto.getAccountNumber());
        assertEquals(9000L, transactionDto.getBalanceSnapshot());
        assertEquals(1000L,transactionDto.getAmount());
        assertEquals(USE,transactionDto.getTransactionType());
        assertEquals(SUCCESS,transactionDto.getTransactionResultType());

    }
}

 

실패 case

@Test
@DisplayName("해당 유저가 존재 x - 잔액 사용 실패 ")
public void useBalance_UserNotFound() throws Exception {
    //given
    AccountUser user = AccountUser.builder()
            .id(12L)
            .name("sy")
            .build();

    given(accountUserRepository.findById(anyLong()))
            .willReturn(Optional.empty());

    //when
    AccountException exception = assertThrows(AccountException.class, () -> transactionService.useBalance(1L,"10000000000",3000L));
    // exception 발생

    //then
    assertEquals(ErrorCode.USER_NOT_FOUND, exception.getErrorCode()); // 에러 발생
}

@Test
@DisplayName("해당 계좌가 존재 x - 잔액 사용 실패 ")
public void deleteAccount_AccountNotFound() throws Exception {
    //given
    AccountUser user = AccountUser.builder()
            .id(12L)
            .name("sy")
            .build();

    given(accountUserRepository.findById(anyLong())).willReturn(Optional.of(user));
    given(accountRepository.findByAccountNumber(anyString())).willReturn(Optional.empty());

    //when
    AccountException exception = assertThrows(AccountException.class, () -> transactionService.useBalance(1L,"10000000000",3000L));
    // exception 발생

    //then
    assertEquals(ErrorCode.ACCOUNT_NOT_FOUND, exception.getErrorCode()); // 에러 발생
}


@Test
@DisplayName("계좌 소유주가 다른 경우 - 잔액 사용 실패 ")
public void deleteAccount_UserAccountUnMatch() throws Exception {
    //given
    AccountUser user = AccountUser.builder()
            .id(12L)
            .name("sy")
            .build();

    AccountUser user2 = AccountUser.builder()
            .id(13L)
            .name("ys")
            .build();

    given(accountUserRepository.findById(anyLong())).willReturn(Optional.of(user));
    given(accountRepository.findByAccountNumber(anyString())).willReturn(Optional.of(Account.builder().accountUser(user2).accountNumber("1000000000").accountStatus(AccountStatus.IN_USE).balance(0L).build())); // 계좌의 유저 아이디 13

    //when
    AccountException exception = assertThrows(AccountException.class, () -> transactionService.useBalance(1L,"10000000000",3000L));
    // exception 발생

    //then
    assertEquals(ErrorCode.USER_ACCOUNT_UN_MATCH, exception.getErrorCode()); // 에러 발생
}

@Test
@DisplayName("계좌가 이미 해지인 경우 - 잔액 사용 실패 ")
public void deleteAccount_alreadyUnregistered() throws Exception {
    //given
    AccountUser user = AccountUser.builder()
            .id(12L)
            .name("sy")
            .build();

    given(accountUserRepository.findById(anyLong())).willReturn(Optional.of(user));
    given(accountRepository.findByAccountNumber(anyString())).willReturn(Optional.of(Account.builder().accountUser(user).accountNumber("1000000000").accountStatus(AccountStatus.UNREGISTERED).balance(0L).build())); // 계좌의 유저 아이디 13

    //when
    AccountException exception = assertThrows(AccountException.class, () ->transactionService.useBalance(1L,"10000000000",3000L));
    // exception 발생

    //then
    assertEquals(ErrorCode.ACCOUNT_ALREADY_UNREGISTRED, exception.getErrorCode()); // 에러 발생
}

@Test
@DisplayName("거래 금액이 잔액보다 큰 경우")
public void failUseBalance() throws Exception {
    //given
    AccountUser user = AccountUser.builder()
            .id(12L)
            .name("sy")
            .build();

    Account account = Account.builder()
            .accountUser(user)
            .accountStatus(IN_USE)
            .accountNumber("1000000012")
            .balance(100L)
            .build();

    given(accountUserRepository.findById(anyLong())).willReturn(Optional.of(user));

    given(accountRepository.findByAccountNumber(anyString())).willReturn(
            Optional.of(account)
    );

    //when
    AccountException exception = assertThrows(AccountException.class, () ->transactionService.useBalance(1L,"10000000000",3000L));

    //then
    assertEquals(ErrorCode.AMOUNT_EXCEED_BALANCE, exception.getErrorCode());
}

@Test
@DisplayName("실패 트랜잭션 저장 성공")
public void saveFailedUseTransaction() throws Exception {
    //given
    AccountUser user = AccountUser.builder()
            .id(12L)
            .name("sy")
            .build();

    Account account = Account.builder()
            .accountUser(user)
            .accountStatus(IN_USE)
            .accountNumber("1000000012")
            .balance(10000L)
            .build();

    given(accountRepository.findByAccountNumber(anyString())).willReturn(
            Optional.of(account)
    );

    given(transactionRepository.save(any())).willReturn(
            Transaction.builder()
                    .account(account)
                    .transactionType(USE)
                    .balanceSnapshot(9000L)
                    .amount(1000L)
                    .transactionResultType(SUCCESS)
                    .transactedAt(LocalDateTime.now())
                    .build()
    );

    ArgumentCaptor<Transaction> captor = ArgumentCaptor.forClass(Transaction.class);

    //when
    transactionService.saveFailedUseTransaction( "1000000012", 200L);

    //then
    verify(transactionRepository, times(1)).save(captor.capture());
    assertEquals(200L, captor.getValue().getAmount());
    assertEquals(10000L,captor.getValue().getBalanceSnapshot());
    assertEquals(FAIL,captor.getValue().getTransactionResultType());

}