diff --git a/application/src/test/java/com/cdx/bas/application/bank/account/BankAccountMapperTest.java b/application/src/test/java/com/cdx/bas/application/bank/account/BankAccountMapperTest.java index 41422c33..3ee38d72 100644 --- a/application/src/test/java/com/cdx/bas/application/bank/account/BankAccountMapperTest.java +++ b/application/src/test/java/com/cdx/bas/application/bank/account/BankAccountMapperTest.java @@ -2,17 +2,18 @@ import com.cdx.bas.application.bank.customer.CustomerEntity; import com.cdx.bas.application.bank.customer.CustomerRepository; -import com.cdx.bas.application.mapper.DtoEntityMapper; import com.cdx.bas.application.bank.transaction.TransactionEntity; -import com.cdx.bas.application.bank.transaction.TransactionTestUtils; -import com.cdx.bas.domain.bank.account.type.AccountType; +import com.cdx.bas.application.mapper.DtoEntityMapper; import com.cdx.bas.domain.bank.account.BankAccount; import com.cdx.bas.domain.bank.account.checking.CheckingBankAccount; +import com.cdx.bas.domain.bank.account.type.AccountType; import com.cdx.bas.domain.bank.customer.Customer; import com.cdx.bas.domain.bank.customer.gender.Gender; import com.cdx.bas.domain.bank.customer.maritalstatus.MaritalStatus; -import com.cdx.bas.domain.money.Money; import com.cdx.bas.domain.bank.transaction.Transaction; +import com.cdx.bas.domain.bank.transaction.status.TransactionStatus; +import com.cdx.bas.domain.bank.transaction.type.TransactionType; +import com.cdx.bas.domain.money.Money; import io.quarkus.test.InjectMock; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.h2.H2DatabaseTestResource; @@ -26,6 +27,8 @@ import java.time.Month; import java.util.*; +import static com.cdx.bas.domain.bank.transaction.status.TransactionStatus.ERROR; +import static com.cdx.bas.domain.bank.transaction.type.TransactionType.CREDIT; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.anyLong; @@ -58,56 +61,64 @@ public void toDto_shouldReturnNullDto_whenEntityIsNull() { @Test public void toEntity_shouldReturnNullEntity_whenDtoIsNull() { + // Act BankAccountEntity entity = bankAccountMapper.toEntity(null); + // Assert assertThat(entity).isNull(); - verifyNoInteractions(customerMapper); } @Test public void toDto_shouldReturnNullDto_whenEntityHasEmptyObject() { + // Act BankAccount dto = bankAccountMapper.toDto(new BankAccountEntity()); + // Assert assertThat(dto).isNull(); - verifyNoInteractions(customerMapper); } @Test public void toDto_shouldMapAccountTypeOnly_whenEntityHasAccount_withOnlyAccountType() { + // Arrange BankAccountEntity entity = new BankAccountEntity(); entity.setType(AccountType.CHECKING); + // Act BankAccount dto = bankAccountMapper.toDto(entity); + // Assert assertThat(dto.getId()).isNull(); assertThat(dto.getType()).isEqualTo(AccountType.CHECKING); assertThat(dto.getBalance()).usingRecursiveComparison().isEqualTo(new Money(null)); assertThat(dto.getCustomersId()).isEmpty(); assertThat(dto.getIssuedTransactions()).isEmpty(); - verifyNoInteractions(customerMapper); } @Test public void toEntity_shouldMapNullValues_whenDtoHasAccount_withOnlyAccountTypeAndId() { + // Arrange BankAccount bankAccount = new CheckingBankAccount(); bankAccount.setId(1L); + + // Act BankAccountEntity entity = bankAccountMapper.toEntity(bankAccount); + // Assert assertThat(entity.getId()).isEqualTo(1L); assertThat(entity.getType()).isEqualTo(AccountType.CHECKING); assertThat(entity.getBalance()).isNull(); assertThat(entity.getCustomers()).isEmpty(); assertThat(entity.getIssuedTransactions()).isEmpty(); - verifyNoInteractions(customerMapper); } @Test public void toDto_shouldMapEveryFieldsOfDto_whenEntityHasValues() { - Instant date = Instant.now(); + // Arrange + Instant timestamp = Instant.now(); BankAccountEntity entity = new BankAccountEntity(); entity.setId(10L); entity.setType(AccountType.CHECKING); @@ -117,18 +128,41 @@ public void toDto_shouldMapEveryFieldsOfDto_whenEntityHasValues() { customers.add(customerEntity); entity.setCustomers(customers); Set transactionEntities = new HashSet<>(); - TransactionEntity transactionEntity1 = TransactionTestUtils.createTransactionEntity(2000L, date); + TransactionEntity transactionEntity1 = createTransactionEntity(2000L, timestamp); transactionEntities.add(transactionEntity1); - TransactionEntity transactionEntity2 = TransactionTestUtils.createTransactionEntity(5000L, date); + TransactionEntity transactionEntity2 = createTransactionEntity(5000L, timestamp); transactionEntities.add(transactionEntity2); entity.setIssuedTransactions(transactionEntities); - Transaction transaction1 = TransactionTestUtils.createTransactionUtils(2000L, date); - Transaction transaction2 = TransactionTestUtils.createTransactionUtils(5000L, date); + Transaction transaction1 = Transaction.builder() + .id(2L) + .type(CREDIT) + .emitterAccountId(2000L) + .receiverAccountId(77L) + .amount(new BigDecimal("100")) + .currency("EUR") + .status(ERROR) + .date(timestamp) + .label("transaction test") + .build(); + Transaction transaction2 = Transaction.builder() + .id(2L) + .type(CREDIT) + .emitterAccountId(5000L) + .receiverAccountId(77L) + .amount(new BigDecimal("100")) + .currency("EUR") + .status(ERROR) + .date(timestamp) + .label("transaction test") + .build(); when(transactionMapper.toDto(transactionEntity1)).thenReturn(transaction1); when(transactionMapper.toDto(transactionEntity2)).thenReturn(transaction2); + + // Act BankAccount dto = bankAccountMapper.toDto(entity); + // Assert assertThat(dto.getId()).isEqualTo(10L); assertThat(dto.getType()).isEqualTo(AccountType.CHECKING); assertThat(dto.getBalance()).usingRecursiveComparison().isEqualTo(new Money(new BigDecimal("1000"))); @@ -145,7 +179,8 @@ public void toDto_shouldMapEveryFieldsOfDto_whenEntityHasValues() { @Test public void toEntity_shouldThrowNoSuchElementException_whenCustomerIsNotFound() { - Instant date = Instant.now(); + // Arrange + Instant timestamp = Instant.now(); BankAccount dto = new CheckingBankAccount(); dto.setId(10L); dto.setType(AccountType.CHECKING); @@ -155,18 +190,40 @@ public void toEntity_shouldThrowNoSuchElementException_whenCustomerIsNotFound() customers.add(customer.getId()); dto.setCustomersId(customers); Set transactions = new HashSet<>(); - Transaction transaction1 = TransactionTestUtils.createTransactionUtils(2000L, date); + Transaction transaction1 = Transaction.builder() + .id(2L) + .emitterAccountId(2000L) + .receiverAccountId(77L) + .amount(new BigDecimal(100)) + .type(TransactionType.CREDIT) + .status(TransactionStatus.ERROR) + .date(timestamp) + .label("transaction test") + .metadata(Map.of("amount_before", "0", "amount_after", "350")) + .build(); transactions.add(transaction1); - Transaction transaction2 = TransactionTestUtils.createTransactionUtils(5000L, date); + Transaction transaction2 = Transaction.builder() + .id(2L) + .emitterAccountId(5000L) + .receiverAccountId(77L) + .amount(new BigDecimal(100)) + .type(TransactionType.CREDIT) + .status(TransactionStatus.ERROR) + .date(timestamp) + .label("transaction test") + .metadata(Map.of("amount_before", "0", "amount_after", "350")) + .build(); transactions.add(transaction2); dto.setIssuedTransactions(transactions); when(customerRepository.findById(anyLong())).thenReturn(Optional.empty()); try { + // Act bankAccountMapper.toEntity(dto); fail(); } catch (NoSuchElementException exception) { + // Assert assertThat(exception.getMessage()).hasToString("Customer entity not found for id: 99"); } @@ -177,7 +234,8 @@ public void toEntity_shouldThrowNoSuchElementException_whenCustomerIsNotFound() @Test public void toEntity_shouldMapEveryFieldsOfEntity_whenDtoHasValues() { - Instant date = Instant.now(); + // Arrange + Instant timestamp = Instant.now(); BankAccount dto = new CheckingBankAccount(); dto.setId(10L); dto.setType(AccountType.CHECKING); @@ -187,23 +245,44 @@ public void toEntity_shouldMapEveryFieldsOfEntity_whenDtoHasValues() { customers.add(customer.getId()); dto.setCustomersId(customers); Set transactions = new HashSet<>(); - Transaction transaction1 = TransactionTestUtils.createTransactionUtils(2000L, date); + Transaction transaction1 = Transaction.builder() + .id(2L) + .emitterAccountId(2000L) + .receiverAccountId(77L) + .amount(new BigDecimal(100)) + .type(TransactionType.CREDIT) + .status(TransactionStatus.ERROR) + .date(timestamp) + .label("transaction test") + .metadata(Map.of("amount_before", "0", "amount_after", "350")) + .build(); transactions.add(transaction1); - Transaction transaction2 = TransactionTestUtils.createTransactionUtils(5000L, date); + Transaction transaction2 = Transaction.builder() + .id(2L) + .emitterAccountId(5000L) + .receiverAccountId(77L) + .amount(new BigDecimal(100)) + .type(TransactionType.CREDIT) + .status(TransactionStatus.ERROR) + .date(timestamp) + .label("transaction test") + .metadata(Map.of("amount_before", "0", "amount_after", "350")) + .build(); transactions.add(transaction2); dto.setIssuedTransactions(transactions); CustomerEntity customerEntity = createCustomerEntityUtils(); when(customerRepository.findByIdOptional(anyLong())).thenReturn(Optional.of(customerEntity)); when(customerMapper.toEntity(customer)).thenReturn(customerEntity); - TransactionEntity transactionEntity1 = TransactionTestUtils.createTransactionEntity(2000L, date); + TransactionEntity transactionEntity1 = createTransactionEntity(2000L, timestamp); when(transactionMapper.toEntity(transaction1)).thenReturn(transactionEntity1); - TransactionEntity transactionEntity2 = TransactionTestUtils.createTransactionEntity(5000L, date); + TransactionEntity transactionEntity2 = createTransactionEntity(5000L, timestamp); when(transactionMapper.toEntity(transaction2)).thenReturn(transactionEntity2); - + // Act BankAccountEntity entity = bankAccountMapper.toEntity(dto); + // Assert assertThat(entity.getId()).isEqualTo(10L); assertThat(entity.getType()).isEqualTo(AccountType.CHECKING); assertThat(entity.getBalance()).usingRecursiveComparison().isEqualTo(new BigDecimal("1000")); @@ -250,4 +329,17 @@ private CustomerEntity createCustomerEntityUtils() { customerEntity.setPhoneNumber("+33642645678"); return customerEntity; } + + private TransactionEntity createTransactionEntity(long id, Instant instantDate) { + TransactionEntity transactionEntity = new TransactionEntity(); + transactionEntity.setId(id); + transactionEntity.setEmitterBankAccountEntity(null); + transactionEntity.setReceiverBankAccountEntity(null); + transactionEntity.setAmount(new BigDecimal("100")); + transactionEntity.setType(TransactionType.CREDIT); + transactionEntity.setStatus(TransactionStatus.ERROR); + transactionEntity.setDate(instantDate); + transactionEntity.setLabel("transaction test"); + return transactionEntity; + } } diff --git a/application/src/test/java/com/cdx/bas/application/bank/account/BankAccountRepositoryTest.java b/application/src/test/java/com/cdx/bas/application/bank/account/BankAccountRepositoryTest.java index f5f54d9a..89c0b72a 100644 --- a/application/src/test/java/com/cdx/bas/application/bank/account/BankAccountRepositoryTest.java +++ b/application/src/test/java/com/cdx/bas/application/bank/account/BankAccountRepositoryTest.java @@ -1,12 +1,13 @@ package com.cdx.bas.application.bank.account; import com.cdx.bas.application.mapper.DtoEntityMapper; -import com.cdx.bas.application.bank.transaction.TransactionTestUtils; -import com.cdx.bas.domain.bank.account.type.AccountType; import com.cdx.bas.domain.bank.account.BankAccount; import com.cdx.bas.domain.bank.account.checking.CheckingBankAccount; -import com.cdx.bas.domain.money.Money; +import com.cdx.bas.domain.bank.account.type.AccountType; import com.cdx.bas.domain.bank.transaction.Transaction; +import com.cdx.bas.domain.bank.transaction.status.TransactionStatus; +import com.cdx.bas.domain.bank.transaction.type.TransactionType; +import com.cdx.bas.domain.money.Money; import io.quarkus.test.InjectMock; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.h2.H2DatabaseTestResource; @@ -37,13 +38,17 @@ public class BankAccountRepositoryTest { @Test @Transactional public void findById_shouldReturnBankAccount_whenAccountIsFound() { + // Arrange long accountId = 1L; Instant date = Instant.now(); BankAccount bankAccount = createBankAccountUtils(accountId, date); when(bankAccountMapper.toDto(any())).thenReturn(bankAccount); + + // Act Optional optionalBankAccount = bankAccountRepository.findById(accountId); - + + // Assert assertThat(optionalBankAccount).contains(bankAccount); verify(bankAccountMapper).toDto(any(BankAccountEntity.class)); verifyNoMoreInteractions(bankAccountMapper); @@ -52,13 +57,15 @@ public void findById_shouldReturnBankAccount_whenAccountIsFound() { @Test @Transactional public void findById_shouldReturnEmptyOptional_whenAccountIsNotFound() { + // Act Optional optionalBankAccount = bankAccountRepository.findById(99999L); - + + // Assert assertThat(optionalBankAccount).isEmpty(); verifyNoInteractions(bankAccountMapper); } - private BankAccount createBankAccountUtils(long accountId, Instant instantDate) { + private BankAccount createBankAccountUtils(long accountId, Instant timestamp) { BankAccount bankAccount = new CheckingBankAccount(); bankAccount.setId(accountId); bankAccount.setType(AccountType.CHECKING); @@ -67,7 +74,17 @@ private BankAccount createBankAccountUtils(long accountId, Instant instantDate) customersId.add(1L); bankAccount.setCustomersId(customersId); HashSet transactionHistory = new HashSet<>(); - transactionHistory.add(TransactionTestUtils.createTransactionUtils(accountId, instantDate)); + transactionHistory.add(Transaction.builder() + .id(2L) + .emitterAccountId(5000L) + .receiverAccountId(77L) + .amount(new BigDecimal(100)) + .type(TransactionType.CREDIT) + .status(TransactionStatus.ERROR) + .date(timestamp) + .label("transaction test") + .metadata(Map.of("amount_before", "0", "amount_after", "350")) + .build()); bankAccount.setIssuedTransactions(transactionHistory); return bankAccount; } diff --git a/application/src/test/java/com/cdx/bas/application/bank/account/BankAccountServiceImplTest.java b/application/src/test/java/com/cdx/bas/application/bank/account/BankAccountServiceImplTest.java index 5ae8b2b5..7163555d 100644 --- a/application/src/test/java/com/cdx/bas/application/bank/account/BankAccountServiceImplTest.java +++ b/application/src/test/java/com/cdx/bas/application/bank/account/BankAccountServiceImplTest.java @@ -1,13 +1,12 @@ package com.cdx.bas.application.bank.account; -import com.cdx.bas.application.bank.transaction.TransactionTestUtils; import com.cdx.bas.domain.bank.account.BankAccount; import com.cdx.bas.domain.bank.account.BankAccountPersistencePort; import com.cdx.bas.domain.bank.account.BankAccountServicePort; +import com.cdx.bas.domain.bank.account.checking.CheckingBankAccount; import com.cdx.bas.domain.bank.account.validation.BankAccountValidator; import com.cdx.bas.domain.bank.transaction.Transaction; import com.cdx.bas.domain.bank.transaction.TransactionServicePort; -import com.cdx.bas.domain.bank.transaction.status.TransactionStatusServicePort; import com.cdx.bas.domain.money.Money; import io.quarkus.test.InjectMock; import io.quarkus.test.common.QuarkusTestResource; @@ -15,17 +14,18 @@ import io.quarkus.test.junit.QuarkusTest; import jakarta.inject.Inject; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; import java.math.BigDecimal; import java.time.Instant; +import java.util.HashSet; +import java.util.List; import java.util.Optional; -import static com.cdx.bas.domain.bank.transaction.status.TransactionStatus.UNPROCESSED; +import static com.cdx.bas.domain.bank.account.type.AccountType.CHECKING; +import static com.cdx.bas.domain.bank.transaction.status.TransactionStatus.ERROR; import static com.cdx.bas.domain.bank.transaction.type.TransactionType.CREDIT; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; -import static org.mockito.Mockito.verifyNoMoreInteractions; @QuarkusTest @QuarkusTestResource(H2DatabaseTestResource.class) @@ -45,11 +45,20 @@ public class BankAccountServiceImplTest { @Test public void findBankAccount_shouldFindBankAccount_whenBankAccountExists() { - BankAccount bankAccount = BankAccountTestUtils.createBankAccountUtils(99L, Money.of(new BigDecimal("100"))); + // Arrange + BankAccount bankAccount = CheckingBankAccount.builder() + .id(99L) + .type(CHECKING) + .balance(Money.of(new BigDecimal("100"))) + .customersId(List.of(99L)) + .build(); when(bankAccountRepository.findById(1L)).thenReturn(Optional.of(bankAccount)); + // Act BankAccount actualBankAccount = bankAccountService.findBankAccount(1L); + + // Assert assertThat(actualBankAccount).isEqualTo(bankAccount); verify(bankAccountRepository).findById(1L); verifyNoMoreInteractions(bankAccountRepository); @@ -58,9 +67,13 @@ public void findBankAccount_shouldFindBankAccount_whenBankAccountExists() { @Test public void findBankAccount_shouldReturnNull_whenBankAccountDoesNotExist() { + // Arrange when(bankAccountRepository.findById(1L)).thenReturn(Optional.empty()); + // Act BankAccount actualBankAccount = bankAccountService.findBankAccount(1L); + + // Assert assertThat(actualBankAccount).isNull(); verify(bankAccountRepository).findById(1L); verifyNoMoreInteractions(bankAccountRepository, bankAccountValidator); @@ -69,11 +82,30 @@ public void findBankAccount_shouldReturnNull_whenBankAccountDoesNotExist() { @Test public void addTransaction_shouldAddTransactionToBankAccount_whenTransactionDoesNotExist() { + // Arrange Instant timestamp = Instant.now(); - BankAccount bankAccount = BankAccountTestUtils.createBankAccountUtils(99L, Money.of(new BigDecimal("100"))); - Transaction transaction = TransactionTestUtils.createTransaction(10L, 99L, timestamp); - - + BankAccount bankAccount = CheckingBankAccount.builder() + .id(99L) + .type(CHECKING) + .balance(Money.of(new BigDecimal("100"))) + .customersId(List.of(99L)) + .issuedTransactions(new HashSet<>()) + .build(); + + // Act + Transaction transaction = Transaction.builder() + .id(10L) + .type(CREDIT) + .emitterAccountId(99L) + .receiverAccountId(77L) + .amount(new BigDecimal("100")) + .currency("EUR") + .status(ERROR) + .date(timestamp) + .label("transaction test") + .build(); + + // Assert BankAccount actualBankAccount = bankAccountService.addTransaction(transaction, bankAccount); assertThat(actualBankAccount.getIssuedTransactions().size()).isEqualTo(1); assertThat(actualBankAccount.getIssuedTransactions()).contains(transaction); @@ -83,17 +115,36 @@ public void addTransaction_shouldAddTransactionToBankAccount_whenTransactionDoes @Test public void addTransaction_shouldUpdateTransactionToBankAccount_whenTransactionExists() { + // Arrange Instant timestamp = Instant.now(); - BankAccount bankAccount = BankAccountTestUtils.createBankAccountUtils(99L, Money.of(new BigDecimal("100"))); - Transaction transaction = TransactionTestUtils.createTransaction(10L, 99L, timestamp); + BankAccount bankAccount = CheckingBankAccount.builder() + .id(99L) + .type(CHECKING) + .balance(Money.of(new BigDecimal("100"))) + .customersId(List.of(99L)) + .issuedTransactions(new HashSet<>()) + .build(); + Transaction transaction = Transaction.builder() + .id(10L) + .type(CREDIT) + .emitterAccountId(99L) + .receiverAccountId(77L) + .amount(new BigDecimal("100")) + .currency("EUR") + .status(ERROR) + .date(timestamp) + .label("transaction test") + .build(); bankAccount.getIssuedTransactions().add(transaction); when(transactionService.mergeTransactions(transaction, transaction)).thenReturn(transaction); + // Act BankAccount actualBankAccount = bankAccountService.addTransaction(transaction, bankAccount); + + // Assert assertThat(actualBankAccount.getIssuedTransactions().size()).isEqualTo(1); assertThat(actualBankAccount.getIssuedTransactions()).contains(transaction); - verify(transactionService).mergeTransactions(transaction, transaction); verifyNoMoreInteractions(transactionService); verifyNoInteractions(bankAccountValidator, bankAccountRepository); @@ -101,9 +152,18 @@ public void addTransaction_shouldUpdateTransactionToBankAccount_whenTransactionE @Test public void updateBankAccount_shouldUpdateBankAccount_whenHasValidBankAccount() { - BankAccount bankAccount = BankAccountTestUtils.createBankAccountUtils(99L, Money.of(new BigDecimal("100"))); - + // Arrange + BankAccount bankAccount = CheckingBankAccount.builder() + .id(99L) + .type(CHECKING) + .balance(Money.of(new BigDecimal("100"))) + .customersId(List.of(99L)) + .build(); + + // Act BankAccount actualBankAccount = bankAccountService.updateBankAccount(bankAccount); + + // Assert assertThat(actualBankAccount).isNull(); verify(bankAccountValidator).validateBankAccount(bankAccount); verify(bankAccountRepository).update(bankAccount); @@ -113,12 +173,35 @@ public void updateBankAccount_shouldUpdateBankAccount_whenHasValidBankAccount() @Test public void transferAmountBetweenAccounts_shouldAddAmountOfMoneyCorrespondingToTransactionAmount_whenTransactionHasAmount() { - Transaction transaction = TransactionTestUtils.createTransaction(10L, 99L, Instant.now()); - BankAccount bankAccountEmitter = BankAccountTestUtils.createBankAccountUtils(99L, Money.of(new BigDecimal("100"))); - BankAccount bankAccountReceiver = BankAccountTestUtils.createBankAccountUtils(100L, Money.of(new BigDecimal("0"))); - + // Arrange + Transaction transaction = Transaction.builder() + .id(10L) + .type(CREDIT) + .emitterAccountId(99L) + .receiverAccountId(77L) + .amount(new BigDecimal("100")) + .currency("EUR") + .status(ERROR) + .date(Instant.now()) + .label("transaction test") + .build(); + BankAccount bankAccountEmitter = CheckingBankAccount.builder() + .id(99L) + .type(CHECKING) + .balance(Money.of(new BigDecimal("100"))) + .customersId(List.of(99L)) + .build(); + BankAccount bankAccountReceiver = CheckingBankAccount.builder() + .id(100L) + .type(CHECKING) + .balance(Money.of(new BigDecimal("0"))) + .customersId(List.of(99L)) + .build(); + + // Act bankAccountService.transferAmountBetweenAccounts(transaction, bankAccountEmitter, bankAccountReceiver); + // Assert assertThat(bankAccountEmitter.getBalance().getAmount()).isEqualTo(new BigDecimal("0")); assertThat(bankAccountReceiver.getBalance().getAmount()).isEqualTo(new BigDecimal("100")); verifyNoInteractions(transactionService, bankAccountValidator, bankAccountRepository); diff --git a/application/src/test/java/com/cdx/bas/application/bank/account/BankAccountTestUtils.java b/application/src/test/java/com/cdx/bas/application/bank/account/BankAccountTestUtils.java deleted file mode 100644 index 470246a1..00000000 --- a/application/src/test/java/com/cdx/bas/application/bank/account/BankAccountTestUtils.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.cdx.bas.application.bank.account; - -import com.cdx.bas.application.bank.customer.CustomerEntity; -import com.cdx.bas.domain.bank.account.type.AccountType; -import com.cdx.bas.domain.bank.account.BankAccount; -import com.cdx.bas.domain.bank.account.checking.CheckingBankAccount; -import com.cdx.bas.domain.money.Money; -import com.cdx.bas.domain.bank.transaction.Transaction; - -import java.math.BigDecimal; -import java.util.*; - -public class BankAccountTestUtils { - - public static BankAccountEntity createBankAccountEntity(long id) { - BankAccountEntity bankAccountEntity = new BankAccountEntity(); - bankAccountEntity.setId(id); - bankAccountEntity.setType(AccountType.CHECKING); - bankAccountEntity.setBalance(new BigDecimal("100")); - CustomerEntity customerEntity = new CustomerEntity(); - customerEntity.setId(99L); - bankAccountEntity.setCustomers(List.of(customerEntity)); - return bankAccountEntity; - } - - public static BankAccount createBankAccountUtils(long accountId, Money amountOfMoney, Transaction...transactions) { - BankAccount bankAccount = new CheckingBankAccount(); - bankAccount.setId(accountId); - bankAccount.setType(AccountType.CHECKING); - bankAccount.setBalance(amountOfMoney); - List customersId = new ArrayList<>(); - customersId.add(99L); - bankAccount.setCustomersId(customersId); - Set transactionHistory = new HashSet<>(); - transactionHistory.addAll(List.of(transactions)); - bankAccount.setIssuedTransactions(transactionHistory); - return bankAccount; - } - - public static BankAccount createBankAccountUtils(long accountId, String amount, Transaction...transactions) { - BankAccount bankAccount = new CheckingBankAccount(); - bankAccount.setId(accountId); - bankAccount.setType(AccountType.CHECKING); - bankAccount.setBalance(new Money(new BigDecimal(amount))); - List customersId = new ArrayList<>(); - customersId.add(99L); - bankAccount.setCustomersId(customersId); - HashSet transactionHistory = new HashSet<>(); - Collections.addAll(transactionHistory, transactions); - bankAccount.setIssuedTransactions(transactionHistory); - return bankAccount; - } -} diff --git a/application/src/test/java/com/cdx/bas/application/bank/customer/CustomerMapperTest.java b/application/src/test/java/com/cdx/bas/application/bank/customer/CustomerMapperTest.java index a32ed3b6..dc2bb237 100644 --- a/application/src/test/java/com/cdx/bas/application/bank/customer/CustomerMapperTest.java +++ b/application/src/test/java/com/cdx/bas/application/bank/customer/CustomerMapperTest.java @@ -1,19 +1,18 @@ package com.cdx.bas.application.bank.customer; import com.cdx.bas.application.bank.account.BankAccountEntity; -import com.cdx.bas.application.mapper.DtoEntityMapper; +import com.cdx.bas.application.bank.account.BankAccountMapper; import com.cdx.bas.application.bank.transaction.TransactionEntity; -import com.cdx.bas.application.bank.transaction.TransactionTestUtils; -import com.cdx.bas.domain.bank.account.type.AccountType; import com.cdx.bas.domain.bank.account.BankAccount; import com.cdx.bas.domain.bank.account.checking.CheckingBankAccount; +import com.cdx.bas.domain.bank.account.type.AccountType; import com.cdx.bas.domain.bank.customer.Customer; import com.cdx.bas.domain.bank.customer.gender.Gender; import com.cdx.bas.domain.bank.customer.maritalstatus.MaritalStatus; -import com.cdx.bas.domain.money.Money; import com.cdx.bas.domain.bank.transaction.Transaction; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; +import com.cdx.bas.domain.bank.transaction.status.TransactionStatus; +import com.cdx.bas.domain.bank.transaction.type.TransactionType; +import com.cdx.bas.domain.money.Money; import io.quarkus.test.InjectMock; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.h2.H2DatabaseTestResource; @@ -29,6 +28,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static com.cdx.bas.domain.bank.transaction.status.TransactionStatus.ERROR; +import static com.cdx.bas.domain.bank.transaction.type.TransactionType.CREDIT; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -36,36 +37,38 @@ @QuarkusTestResource(H2DatabaseTestResource.class) public class CustomerMapperTest { + @InjectMock + BankAccountMapper bankAccountMapper; + @Inject CustomerMapper customerMapper; - @InjectMock - private DtoEntityMapper bankAccountMapper; - @Test public void toDto_shouldReturnNullDto_whenEntityIsNull() { + // Act Customer dto = customerMapper.toDto(null); - + + // Assert assertThat(dto).isNull(); - verifyNoInteractions(bankAccountMapper); } @Test public void toEntity_shouldReturnNullEntity_whenDtoIsNull() { - Customer dto = null; + // Act + CustomerEntity entity = customerMapper.toEntity(null); - CustomerEntity entity = customerMapper.toEntity(dto); - + // Assert assertThat(entity).isNull(); - verifyNoInteractions(bankAccountMapper); } @Test - public void toDto_shouldMapNullValues_whenEntityValuesNotDefined() throws JsonMappingException, JsonProcessingException { + public void toDto_shouldMapNullValues_whenEntityValuesNotDefined() { + // Act Customer dto = customerMapper.toDto(new CustomerEntity()); - + + // Assert assertThat(dto.getId()).isNull(); assertThat(dto.getFirstName()).isNull(); assertThat(dto.getLastName()).isNull(); @@ -85,9 +88,11 @@ public void toDto_shouldMapNullValues_whenEntityValuesNotDefined() throws JsonMa } @Test - public void toEntity_shouldMapNullValues_whenDtoValuesNotDefined() throws JsonProcessingException { + public void toEntity_shouldMapNullValues_whenDtoValuesNotDefined() { + // Act CustomerEntity entity = customerMapper.toEntity(new Customer()); - + + // Assert assertThat(entity.getId()).isNull(); assertThat(entity.getFirstName()).isNull(); assertThat(entity.getLastName()).isNull(); @@ -102,12 +107,12 @@ public void toEntity_shouldMapNullValues_whenDtoValuesNotDefined() throws JsonPr assertThat(entity.getPhoneNumber()).isNull(); assertThat(entity.getAccounts()).isEmpty(); assertThat(entity.getMetadata()).isNull(); - verifyNoInteractions(bankAccountMapper); } @Test public void toDto_shouldMapDtoValues_whenEntityHasValues() { + // Arrange CustomerEntity entity = new CustomerEntity(); entity.setId(1L); entity.setFirstName("Paul"); @@ -124,7 +129,7 @@ public void toDto_shouldMapDtoValues_whenEntityHasValues() { Instant instantDate = Instant.now(); BankAccountEntity accountEntity1 = createBankAccountEntity(10L, instantDate); BankAccountEntity accountEntity2 = createBankAccountEntity(11L, instantDate); - List accounts = new ArrayList(); + List accounts = new ArrayList<>(); accounts.add(accountEntity1); accounts.add(accountEntity2); entity.setAccounts(accounts); @@ -136,9 +141,11 @@ public void toDto_shouldMapDtoValues_whenEntityHasValues() { BankAccount account2 = createBankAccount(11L, instantDate); when(bankAccountMapper.toDto(accountEntity1)).thenReturn(account1); when(bankAccountMapper.toDto(accountEntity2)).thenReturn(account2); - + + // Act Customer dto = customerMapper.toDto(entity); - + + // Assert assertThat(dto.getId()).isEqualTo(1L); assertThat(dto.getFirstName()).hasToString("Paul"); assertThat(dto.getLastName()).hasToString("Martin"); @@ -152,11 +159,10 @@ public void toDto_shouldMapDtoValues_whenEntityHasValues() { assertThat(dto.getEmail()).hasToString("jean.dupont@yahoo.fr"); assertThat(dto.getPhoneNumber()).hasToString("+33642645678"); assertThat(dto.getAccounts()).hasSize(2); - Set accoutsToCompar = Stream.of(account1, account2).collect(Collectors.toSet()); - assertThat(dto.getAccounts()).containsExactlyInAnyOrderElementsOf(accoutsToCompar); + Set accountsToCompare = Stream.of(account1, account2).collect(Collectors.toSet()); + assertThat(dto.getAccounts()).containsExactlyInAnyOrderElementsOf(accountsToCompare); assertThat(dto.getMetadata().get("contact_preferences")).isEqualTo("email"); assertThat(dto.getMetadata().get("annual_salary")).isEqualTo("52000"); - verify(bankAccountMapper).toDto(accountEntity1); verify(bankAccountMapper).toDto(accountEntity2); verifyNoMoreInteractions(bankAccountMapper); @@ -164,6 +170,7 @@ public void toDto_shouldMapDtoValues_whenEntityHasValues() { @Test public void toEntity_shouldMapEntityValues_whenDtoHasValues() { + // Arrange Customer model = new Customer(); model.setId(1L); model.setFirstName("Paul"); @@ -180,7 +187,7 @@ public void toEntity_shouldMapEntityValues_whenDtoHasValues() { Instant instantDate = Instant.now(); BankAccount account1 = createBankAccount(10L, instantDate); BankAccount account2 = createBankAccount(11L, instantDate); - List accounts = new ArrayList(); + List accounts = new ArrayList<>(); accounts.add(account1); accounts.add(account2); model.setAccounts(accounts); @@ -194,9 +201,11 @@ public void toEntity_shouldMapEntityValues_whenDtoHasValues() { BankAccountEntity accountEntity2 = createBankAccountEntity(11L, instantDate); when(bankAccountMapper.toEntity(account1)).thenReturn(accountEntity1); when(bankAccountMapper.toEntity(account2)).thenReturn(accountEntity2); - + + // Act CustomerEntity entity = customerMapper.toEntity(model); - + + // Assert assertThat(entity.getId()).isEqualTo(1L); assertThat(entity.getFirstName()).hasToString("Paul"); assertThat(entity.getLastName()).hasToString("Martin"); @@ -210,16 +219,15 @@ public void toEntity_shouldMapEntityValues_whenDtoHasValues() { assertThat(entity.getEmail()).hasToString("jean.dupont@yahoo.fr"); assertThat(entity.getPhoneNumber()).hasToString("+33642645678"); assertThat(entity.getAccounts()).hasSize(2); - Set accountsToCompar = Stream.of(accountEntity1, accountEntity2).collect(Collectors.toSet()); - assertThat(entity.getAccounts()).containsExactlyInAnyOrderElementsOf(accountsToCompar); + Set accountsToCompare = Stream.of(accountEntity1, accountEntity2).collect(Collectors.toSet()); + assertThat(entity.getAccounts()).containsExactlyInAnyOrderElementsOf(accountsToCompare); assertThat(entity.getMetadata()).hasToString("{\"contact_preferences\":\"email\",\"annual_salary\":\"48000\"}"); - verify(bankAccountMapper).toEntity(account1); verify(bankAccountMapper).toEntity(account2); verifyNoMoreInteractions(bankAccountMapper); } - private BankAccount createBankAccount(long accountId, Instant instantDate) { + private BankAccount createBankAccount(long accountId, Instant timestamp) { BankAccount bankAccount = new CheckingBankAccount(); bankAccount.setId(accountId); bankAccount.setType(AccountType.CHECKING); @@ -228,9 +236,39 @@ private BankAccount createBankAccount(long accountId, Instant instantDate) { customersId.add(99L); bankAccount.setCustomersId(customersId); Set transactions = new HashSet<>(); - transactions.add(TransactionTestUtils.createTransaction(99L, accountId, instantDate)); - transactions.add(TransactionTestUtils.createTransaction(100L, accountId, instantDate)); - transactions.add(TransactionTestUtils.createTransaction(100L, accountId, instantDate)); + transactions.add(Transaction.builder() + .id(100L) + .type(CREDIT) + .emitterAccountId(accountId) + .receiverAccountId(77L) + .amount(new BigDecimal("100")) + .currency("EUR") + .status(ERROR) + .date(timestamp) + .label("transaction test") + .build()); + transactions.add(Transaction.builder() + .id(100L) + .type(CREDIT) + .emitterAccountId(accountId) + .receiverAccountId(77L) + .amount(new BigDecimal("100")) + .currency("EUR") + .status(ERROR) + .date(timestamp) + .label("transaction test") + .build()); + transactions.add(Transaction.builder() + .id(100L) + .type(CREDIT) + .emitterAccountId(accountId) + .receiverAccountId(77L) + .amount(new BigDecimal("100")) + .currency("EUR") + .status(ERROR) + .date(timestamp) + .label("transaction test") + .build()); bankAccount.setIssuedTransactions(transactions); return bankAccount; } @@ -244,9 +282,22 @@ private BankAccountEntity createBankAccountEntity(long id, Instant instantDate) customersId.add(new CustomerEntity()); bankAccountEntity.setCustomers(customersId); HashSet transactionEntities = new HashSet<>(); - transactionEntities.add(TransactionTestUtils.createTransactionEntity(99L, instantDate)); - transactionEntities.add(TransactionTestUtils.createTransactionEntity(100L, instantDate)); + transactionEntities.add(createTransactionEntity(99L, instantDate)); + transactionEntities.add(createTransactionEntity(100L, instantDate)); bankAccountEntity.setIssuedTransactions(transactionEntities); return bankAccountEntity; } + + private TransactionEntity createTransactionEntity(long id, Instant instantDate) { + TransactionEntity transactionEntity = new TransactionEntity(); + transactionEntity.setId(id); + transactionEntity.setEmitterBankAccountEntity(null); + transactionEntity.setReceiverBankAccountEntity(null); + transactionEntity.setAmount(new BigDecimal("100")); + transactionEntity.setType(TransactionType.CREDIT); + transactionEntity.setStatus(TransactionStatus.ERROR); + transactionEntity.setDate(instantDate); + transactionEntity.setLabel("transaction test"); + return transactionEntity; + } } diff --git a/application/src/test/java/com/cdx/bas/application/bank/transaction/TransactionMapperTest.java b/application/src/test/java/com/cdx/bas/application/bank/transaction/TransactionMapperTest.java index 97c5b8cd..e08a82db 100644 --- a/application/src/test/java/com/cdx/bas/application/bank/transaction/TransactionMapperTest.java +++ b/application/src/test/java/com/cdx/bas/application/bank/transaction/TransactionMapperTest.java @@ -2,7 +2,8 @@ import com.cdx.bas.application.bank.account.BankAccountEntity; import com.cdx.bas.application.bank.account.BankAccountRepository; -import com.cdx.bas.application.bank.account.BankAccountTestUtils; +import com.cdx.bas.application.bank.customer.CustomerEntity; +import com.cdx.bas.domain.bank.account.type.AccountType; import com.cdx.bas.domain.bank.transaction.Transaction; import com.cdx.bas.domain.bank.transaction.status.TransactionStatus; import com.cdx.bas.domain.bank.transaction.type.TransactionType; @@ -15,7 +16,7 @@ import java.math.BigDecimal; import java.time.Instant; -import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Optional; @@ -94,11 +95,21 @@ public void toEntity_shouldThrowException_whenTransactionDto_doesNotHave_receive @Test public void toDto_shouldMapEntityValues_whenEntityHasValues() { - Instant date = Instant.now(); + Instant timestamp = Instant.now(); long emitterAccountId = 99L; long receiverAccountId = 77L; Map metadata = Map.of("amount_before", "0", "amount_after", "100"); - TransactionEntity transactionEntity = TransactionTestUtils.createTransactionEntityUtils(emitterAccountId, receiverAccountId, date); + TransactionEntity transactionEntity = new TransactionEntity(); + transactionEntity.setId(10L); + transactionEntity.setEmitterBankAccountEntity(createBankAccountEntity(emitterAccountId)); + transactionEntity.setReceiverBankAccountEntity(createBankAccountEntity(receiverAccountId)); + transactionEntity.setAmount(new BigDecimal("100")); + transactionEntity.setCurrency("EUR"); + transactionEntity.setType(TransactionType.CREDIT); + transactionEntity.setStatus(TransactionStatus.COMPLETED); + transactionEntity.setDate(timestamp); + transactionEntity.setLabel("transaction test"); + transactionEntity.setMetadata("{\"amount_after\" : \"100\", \"amount_before\" : \"0\"}"); Transaction dto = transactionMapper.toDto(transactionEntity); @@ -109,24 +120,32 @@ public void toDto_shouldMapEntityValues_whenEntityHasValues() { assertThat(dto.getCurrency()).isEqualTo("EUR"); assertThat(dto.getType()).isEqualTo(TransactionType.CREDIT); assertThat(dto.getStatus()).isEqualTo(TransactionStatus.COMPLETED); - assertThat(dto.getDate()).isEqualTo(date); + assertThat(dto.getDate()).isEqualTo(timestamp); assertThat(dto.getLabel()).hasToString("transaction test"); assertThat(dto.getMetadata()).usingRecursiveComparison().isEqualTo(metadata); } @Test public void toEntity_shouldMapEntityValues_whenDtoHasValues() { - Instant date = Instant.now(); + Instant timestamp = Instant.now(); long emitterAccountId = 99L; long receiverAccountId = 77L; - String strMetadata = "{\"amount_after\":\"100\",\"amount_before\":\"0\"}"; - Map metadata = new HashMap<>(); - metadata.put("amount_before", "0"); - metadata.put("amount_after", "100"); - BankAccountEntity emitterBankAccountEntity = BankAccountTestUtils.createBankAccountEntity(emitterAccountId); - BankAccountEntity receiverBankAccountEntity = BankAccountTestUtils.createBankAccountEntity(receiverAccountId); - Transaction transaction = TransactionTestUtils.createTransactionUtils(emitterAccountId, receiverAccountId, date); - transaction.setMetadata(metadata); + + Map metadata = Map.of("amount_before", "0", "amount_after", "100"); + BankAccountEntity emitterBankAccountEntity = createBankAccountEntity(emitterAccountId); + BankAccountEntity receiverBankAccountEntity = createBankAccountEntity(receiverAccountId); + Transaction transaction = Transaction.builder() + .id(10L) + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal(100)) + .currency("EUR") + .type(TransactionType.CREDIT) + .status(TransactionStatus.COMPLETED) + .date(timestamp) + .label("transaction test") + .metadata(metadata) + .build(); when(bankAccountRepository.findByIdOptional(99L)).thenReturn(Optional.of(emitterBankAccountEntity)); when(bankAccountRepository.findByIdOptional(77L)).thenReturn(Optional.of(receiverBankAccountEntity)); @@ -140,8 +159,23 @@ public void toEntity_shouldMapEntityValues_whenDtoHasValues() { assertThat(entity.getCurrency()).isEqualTo("EUR"); assertThat(entity.getType()).isEqualTo(TransactionType.CREDIT); assertThat(entity.getStatus()).isEqualTo(TransactionStatus.COMPLETED); - assertThat(entity.getDate()).isEqualTo(date); + assertThat(entity.getDate()).isEqualTo(timestamp); assertThat(entity.getLabel()).hasToString("transaction test"); - assertThat(entity.getMetadata()).contains(strMetadata); + String amountBefore = "\"amount_before\":\"0\""; + String amountAfter = "\"amount_after\":\"100\""; + assertThat(entity.getMetadata()) + .contains(amountBefore) + .contains(amountAfter); + } + + public BankAccountEntity createBankAccountEntity(long id) { + BankAccountEntity bankAccountEntity = new BankAccountEntity(); + bankAccountEntity.setId(id); + bankAccountEntity.setType(AccountType.CHECKING); + bankAccountEntity.setBalance(new BigDecimal("100")); + CustomerEntity customerEntity = new CustomerEntity(); + customerEntity.setId(99L); + bankAccountEntity.setCustomers(List.of(customerEntity)); + return bankAccountEntity; } } \ No newline at end of file diff --git a/application/src/test/java/com/cdx/bas/application/bank/transaction/TransactionServiceImplTest.java b/application/src/test/java/com/cdx/bas/application/bank/transaction/TransactionServiceImplTest.java index 8602aba0..9f8f2e3a 100644 --- a/application/src/test/java/com/cdx/bas/application/bank/transaction/TransactionServiceImplTest.java +++ b/application/src/test/java/com/cdx/bas/application/bank/transaction/TransactionServiceImplTest.java @@ -1,16 +1,15 @@ package com.cdx.bas.application.bank.transaction; -import com.cdx.bas.domain.bank.transaction.*; +import com.cdx.bas.domain.bank.transaction.NewTransaction; +import com.cdx.bas.domain.bank.transaction.Transaction; +import com.cdx.bas.domain.bank.transaction.TransactionException; +import com.cdx.bas.domain.bank.transaction.TransactionPersistencePort; +import com.cdx.bas.domain.bank.transaction.type.TransactionType; import com.cdx.bas.domain.bank.transaction.type.TransactionTypeProcessingServicePort; import com.cdx.bas.domain.bank.transaction.validation.TransactionValidator; -import io.quarkus.test.InjectMock; -import io.quarkus.test.Mock; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.h2.H2DatabaseTestResource; import io.quarkus.test.junit.QuarkusTest; -import jakarta.inject.Inject; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -40,15 +39,18 @@ public class TransactionServiceImplTest { @Test public void getAll_shouldReturnAllTransactions_whenRepositoryReturnsTransactions() { + // Arrange Set transactions = Set.of( Transaction.builder().id(1L).build(), Transaction.builder().id(2L).build(), Transaction.builder().id(3L).build() ); - when(transactionRepository.getAll()).thenReturn(transactions); + // Act Set actual = transactionService.getAll(); + + // Assert assertThat(actual).isEqualTo(transactions); verify(transactionRepository).getAll(); verifyNoMoreInteractions(transactionRepository); @@ -56,15 +58,18 @@ public void getAll_shouldReturnAllTransactions_whenRepositoryReturnsTransactions @Test public void findAllByStatus_shouldReturnTransactionCorrespondingToStatus_whenStatusIsValid() { + // Arrange Set transactions = Set.of( Transaction.builder().id(1L).status(COMPLETED).build(), Transaction.builder().id(2L).status(COMPLETED).build(), Transaction.builder().id(3L).status(COMPLETED).build() ); - when(transactionRepository.findAllByStatus(COMPLETED)).thenReturn(transactions); + // Act Set actual = transactionService.findAllByStatus("COMPLETED"); + + // Assert assertThat(actual).isEqualTo(transactions); verify(transactionRepository).findAllByStatus(COMPLETED); verifyNoMoreInteractions(transactionRepository); @@ -72,9 +77,11 @@ public void findAllByStatus_shouldReturnTransactionCorrespondingToStatus_whenSta @Test public void findAllByStatus_shouldThrowException_whenStatusIsInvalid() { + // Act try { transactionService.findAllByStatus("INVALID"); } catch (IllegalArgumentException exception) { + // Assert assertThat(exception.getMessage()).isEqualTo("Invalid status: INVALID"); } verifyNoInteractions(transactionRepository); @@ -84,9 +91,23 @@ public void findAllByStatus_shouldThrowException_whenStatusIsInvalid() { public void createTransaction_shouldCreateTransaction_whenTransactionIsValid() { // Arrange Instant timestamp = Instant.parse("2024-03-14T12:00:00Z"); - NewTransaction newTransaction = TransactionTestUtils.createNewTransactionUtils(100L, "transaction test"); - Transaction transactionToCreate = TransactionTestUtils.createTransactionUtils(null, 100L, timestamp, "transaction test"); - + NewTransaction newTransaction = NewTransaction.builder() + .amount(new BigDecimal("100")) + .emitterAccountId(99L) + .receiverAccountId(77L) + .type(TransactionType.CREDIT) + .label("transaction test") + .build(); + Transaction transactionToCreate = Transaction.builder() + .id(null) + .emitterAccountId(99L) + .receiverAccountId(77L) + .amount(new BigDecimal("100")) + .label("transaction test") + .type(TransactionType.CREDIT) + .status(UNPROCESSED) + .date(timestamp) + .build(); when(clock.instant()).thenReturn(timestamp); // Act @@ -100,6 +121,7 @@ public void createTransaction_shouldCreateTransaction_whenTransactionIsValid() { @Test public void createTransaction_shouldThrowException_whenTransactionIsInvalid() { + // Arrange Instant timestamp = Instant.parse("2024-03-14T12:00:00Z"); Transaction invalidTransaction = new Transaction(); invalidTransaction.setDate(timestamp); @@ -109,8 +131,10 @@ public void createTransaction_shouldThrowException_whenTransactionIsInvalid() { doThrow(new TransactionException("invalid transaction...")).when(transactionValidator).validateNewTransaction(invalidTransaction); try { + // Act transactionService.createTransaction(new NewTransaction()); } catch (TransactionException exception) { + // Assert assertThat(exception.getMessage()).isEqualTo("invalid transaction..."); } verify(transactionValidator).validateNewTransaction(invalidTransaction); @@ -120,6 +144,7 @@ public void createTransaction_shouldThrowException_whenTransactionIsInvalid() { @Test public void mergeTransaction_shouldMergeOldTransactionWithNewTransaction_whenOldTransactionAndNewTransactionAreValid() { + // Arrange Transaction oldTransaction = Transaction.builder() .id(1L) .amount(new BigDecimal(100)) @@ -145,6 +170,7 @@ public void mergeTransaction_shouldMergeOldTransactionWithNewTransaction_whenOld .label(labelAfter) .build(); + // Act Transaction actualTransaction = transactionService.mergeTransactions(oldTransaction, newTransaction); oldTransaction.setId(2L); @@ -155,11 +181,14 @@ public void mergeTransaction_shouldMergeOldTransactionWithNewTransaction_whenOld oldTransaction.setStatus(UNPROCESSED); oldTransaction.setDate(dateAfter); oldTransaction.setLabel(labelAfter); + + // Assert assertThat(actualTransaction).isEqualTo(oldTransaction); } @Test public void findTransaction_shouldFindTransaction_whenTransactionExists() { + // Arrange Transaction transaction = Transaction.builder() .id(1L) .amount(new BigDecimal(100)) @@ -170,10 +199,12 @@ public void findTransaction_shouldFindTransaction_whenTransactionExists() { .date(Instant.now()) .label("deposit of 100 euros") .build(); - when(transactionRepository.findById(1L)).thenReturn(Optional.of(transaction)); + // Act Transaction actualTransaction = transactionService.findTransaction(1L); + + // Assert assertThat(actualTransaction).isEqualTo(transaction); verify(transactionRepository).findById(1L); verifyNoMoreInteractions(transactionRepository); @@ -181,9 +212,13 @@ public void findTransaction_shouldFindTransaction_whenTransactionExists() { @Test public void findTransaction_shouldReturnNull_whenTransactionDoesNotExist() { + // Arrange when(transactionRepository.findById(1L)).thenReturn(Optional.empty()); + // Act Transaction actualTransaction = transactionService.findTransaction(1L); + + // Assert assertThat(actualTransaction).isNull(); verify(transactionRepository).findById(1L); verifyNoMoreInteractions(transactionRepository); @@ -191,6 +226,7 @@ public void findTransaction_shouldReturnNull_whenTransactionDoesNotExist() { @Test public void process_shouldProcessBankAccountCredit_whenTransactionHasCreditType() { + // Arrange Transaction transaction = Transaction.builder() .id(1L) .amount(new BigDecimal(100)) @@ -202,13 +238,17 @@ public void process_shouldProcessBankAccountCredit_whenTransactionHasCreditType( .label("deposit of 100 euros") .build(); + // Act transactionService.process(transaction); + + // Assert verify(transactionTypeProcessingServicePort).credit(transaction); verifyNoMoreInteractions(transactionTypeProcessingServicePort); } @Test public void process_shouldProcessBankAccountDeposit_whenTransactionHasDepositType() { + // Arrange Transaction transaction = Transaction.builder() .id(1L) .amount(new BigDecimal(100)) @@ -220,7 +260,10 @@ public void process_shouldProcessBankAccountDeposit_whenTransactionHasDepositTyp .label("deposit of 100 euros") .build(); + // Act transactionService.process(transaction); + + // Assert verify(transactionTypeProcessingServicePort).deposit(transaction); verifyNoMoreInteractions(transactionTypeProcessingServicePort); } diff --git a/application/src/test/java/com/cdx/bas/application/bank/transaction/TransactionTestUtils.java b/application/src/test/java/com/cdx/bas/application/bank/transaction/TransactionTestUtils.java deleted file mode 100644 index 3a6d1421..00000000 --- a/application/src/test/java/com/cdx/bas/application/bank/transaction/TransactionTestUtils.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.cdx.bas.application.bank.transaction; - -import com.cdx.bas.application.bank.account.BankAccountTestUtils; -import com.cdx.bas.domain.bank.transaction.NewTransaction; -import com.cdx.bas.domain.bank.transaction.Transaction; -import com.cdx.bas.domain.bank.transaction.status.TransactionStatus; -import com.cdx.bas.domain.bank.transaction.type.TransactionType; - -import java.math.BigDecimal; -import java.time.Instant; -import java.util.Map; - -import static com.cdx.bas.domain.bank.transaction.status.TransactionStatus.ERROR; -import static com.cdx.bas.domain.bank.transaction.type.TransactionType.CREDIT; - -public class TransactionTestUtils { - public static Transaction createTransactionUtils(long emitterAccountId, long receiverAccountId, - BigDecimal amount, TransactionStatus status, - Instant date, Map metadata) { - return Transaction.builder() - .id(1L) - .amount(amount) - .currency("EUR") - .emitterAccountId(emitterAccountId) - .receiverAccountId(receiverAccountId) - .type(TransactionType.CREDIT) - .status(status) - .date(date) - .label("transaction of " + amount) - .metadata(metadata).build(); - } - - public static Transaction createTransactionUtils(Long id, Long amount, Instant date, String label) { - return Transaction.builder() - .id(id) - .amount(new BigDecimal(amount)) - .emitterAccountId(99L) - .receiverAccountId(77L) - .type(TransactionType.CREDIT) - .status(TransactionStatus.UNPROCESSED) - .date(date) - .label(label) - .build(); - } - - public static NewTransaction createNewTransactionUtils(long amount, String label) { - return NewTransaction.builder() - .amount(new BigDecimal(amount)) - .emitterAccountId(99L) - .receiverAccountId(77L) - .type(TransactionType.CREDIT) - .label(label) - .build(); - } - - public static Transaction createTransactionUtils(Long emitterAccountId, Long receiverAccountId, Instant instantDate) { - Map metadata = Map.of("amount_before", "0", "amount_after", "100"); - return Transaction.builder() - .id(10L) - .emitterAccountId(emitterAccountId) - .receiverAccountId(receiverAccountId) - .amount(new BigDecimal(100)) - .currency("EUR") - .type(TransactionType.CREDIT) - .status(TransactionStatus.COMPLETED) - .date(instantDate) - .label("transaction test") - .metadata(metadata) - .build(); - } - - public static Transaction createTransaction(Long id, Long emitterBankAccount, Instant instantDate) { - return Transaction.builder() - .id(id) - .type(CREDIT) - .emitterAccountId(emitterBankAccount) - .receiverAccountId(77L) - .amount(new BigDecimal("100")) - .currency("EUR") - .status(ERROR) - .date(instantDate) - .label("transaction test") - .build(); - } - - public static Transaction createTransactionUtils(long accountId, Instant instantDate) { - Map metadata = Map.of("amount_before", "0", "amount_after", "350"); - return Transaction.builder() - .id(2L) - .emitterAccountId(accountId) - .receiverAccountId(77L) - .amount(new BigDecimal(100)) - .type(TransactionType.CREDIT) - .status(TransactionStatus.ERROR) - .date(instantDate) - .label("transaction test") - .metadata(metadata) - .build(); - } - - public static TransactionEntity createTransactionEntity(long id, Instant instantDate) { - TransactionEntity transactionEntity = new TransactionEntity(); - transactionEntity.setId(id); - transactionEntity.setEmitterBankAccountEntity(null); - transactionEntity.setReceiverBankAccountEntity(null); - transactionEntity.setAmount(new BigDecimal("100")); - transactionEntity.setType(TransactionType.CREDIT); - transactionEntity.setStatus(TransactionStatus.ERROR); - transactionEntity.setDate(instantDate); - transactionEntity.setLabel("transaction test"); - return transactionEntity; - } - - public static TransactionEntity createTransactionEntityUtils(long emitterAccountId, long receiverAccountId, Instant instantDate) { - TransactionEntity transactionEntity = new TransactionEntity(); - transactionEntity.setId(10L); - transactionEntity.setEmitterBankAccountEntity(BankAccountTestUtils.createBankAccountEntity(emitterAccountId)); - transactionEntity.setReceiverBankAccountEntity(BankAccountTestUtils.createBankAccountEntity(receiverAccountId)); - transactionEntity.setAmount(new BigDecimal("100")); - transactionEntity.setCurrency("EUR"); - transactionEntity.setType(TransactionType.CREDIT); - transactionEntity.setStatus(TransactionStatus.COMPLETED); - transactionEntity.setDate(instantDate); - transactionEntity.setLabel("transaction test"); - transactionEntity.setMetadata("{\"amount_after\" : \"100\", \"amount_before\" : \"0\"}"); - return transactionEntity; - } -} diff --git a/application/src/test/java/com/cdx/bas/application/bank/transaction/TransactionTypeProcessingServiceImplTest.java b/application/src/test/java/com/cdx/bas/application/bank/transaction/TransactionTypeProcessingServiceImplTest.java index 8c284b86..7e93dec7 100644 --- a/application/src/test/java/com/cdx/bas/application/bank/transaction/TransactionTypeProcessingServiceImplTest.java +++ b/application/src/test/java/com/cdx/bas/application/bank/transaction/TransactionTypeProcessingServiceImplTest.java @@ -1,9 +1,9 @@ package com.cdx.bas.application.bank.transaction; -import com.cdx.bas.application.bank.account.BankAccountTestUtils; import com.cdx.bas.domain.bank.account.BankAccount; import com.cdx.bas.domain.bank.account.BankAccountException; import com.cdx.bas.domain.bank.account.BankAccountServicePort; +import com.cdx.bas.domain.bank.account.checking.CheckingBankAccount; import com.cdx.bas.domain.bank.transaction.Transaction; import com.cdx.bas.domain.bank.transaction.TransactionException; import com.cdx.bas.domain.bank.transaction.status.TransactionStatusServicePort; @@ -17,10 +17,9 @@ import java.math.BigDecimal; import java.time.Instant; -import java.util.HashMap; -import java.util.Map; -import java.util.NoSuchElementException; +import java.util.*; +import static com.cdx.bas.domain.bank.account.type.AccountType.CHECKING; import static com.cdx.bas.domain.bank.transaction.status.TransactionStatus.*; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -39,21 +38,44 @@ class TransactionTypeProcessingServiceImplTest { @Test public void credit_shouldThrowNoSuchElementException_whenEmitterAccountIsNotFound() { + // Arrange long emitterAccountId = 99L; long receiverAccountId = 77L; - Money amountOfMoney = Money.of(new BigDecimal("0")); Instant instantDate = Instant.now(); - Transaction transaction = TransactionTestUtils.createTransactionUtils(emitterAccountId, receiverAccountId, new BigDecimal("1000"), UNPROCESSED, instantDate, new HashMap<>()); + Transaction transaction = Transaction.builder() + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(UNPROCESSED) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); Map metadata = Map.of("error", "Emitter bank account 99 is not found."); - Transaction erroredTransaction = TransactionTestUtils.createTransactionUtils(emitterAccountId, receiverAccountId, new BigDecimal("1000"), ERROR, instantDate, metadata); + Transaction erroredTransaction = Transaction.builder() + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(ERROR) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); when(bankAccountService.findBankAccount(emitterAccountId)).thenThrow(new NoSuchElementException("Emitter bank account 99 is not found.")); when(transactionStatusService.setStatus(eq(transaction), eq(ERROR), eq(metadata))).thenReturn(erroredTransaction); + // Act Transaction returnedTransaction = transactionProcessingService.credit(transaction); + // Assert assertThat(returnedTransaction).usingRecursiveComparison() - .isEqualTo(TransactionTestUtils.createTransactionUtils(emitterAccountId, receiverAccountId, new BigDecimal("1000"), ERROR, instantDate, metadata)); + .isEqualTo(Transaction.builder() + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(ERROR) + .date(instantDate) + .metadata(new HashMap<>()) + .build()); verify(bankAccountService).findBankAccount(eq(emitterAccountId)); verify(transactionStatusService).setStatus(eq(transaction), eq(ERROR), eq(metadata)); verifyNoMoreInteractions(bankAccountService, transactionStatusService); @@ -61,23 +83,53 @@ public void credit_shouldThrowNoSuchElementException_whenEmitterAccountIsNotFoun @Test public void credit_shouldThrowNoSuchElementException_whenReceiverAccountIsNotFound() { + // Arrange long emitterAccountId = 99L; long receiverAccountId = 77L; Money amountOfMoney = Money.of(new BigDecimal("0")); Instant instantDate = Instant.now(); - Transaction transaction = TransactionTestUtils.createTransactionUtils(emitterAccountId, receiverAccountId, new BigDecimal("1000"), UNPROCESSED, instantDate, new HashMap<>()); + Transaction transaction = Transaction.builder() + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(UNPROCESSED) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); Map metadata = Map.of("error", "Receiver bank account 77 is not found."); - Transaction erroredTransaction = TransactionTestUtils.createTransactionUtils(emitterAccountId, receiverAccountId, new BigDecimal("1000"), ERROR, instantDate, metadata); - BankAccount emitterBankAccount = BankAccountTestUtils.createBankAccountUtils(emitterAccountId, "0", transaction); + Transaction erroredTransaction = Transaction.builder() + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(ERROR) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); + BankAccount emitterBankAccount = CheckingBankAccount.builder() + .id(emitterAccountId) + .type(CHECKING) + .balance(amountOfMoney) + .customersId(List.of(99L)) + .issuedTransactions(Set.of(transaction)) + .build(); when(bankAccountService.findBankAccount(emitterAccountId)).thenReturn(emitterBankAccount); when(bankAccountService.findBankAccount(receiverAccountId)).thenThrow(new NoSuchElementException("Receiver bank account 77 is not found.")); when(transactionStatusService.setStatus(eq(transaction), eq(ERROR), eq(metadata))).thenReturn(erroredTransaction); + // Act Transaction returnedTransaction = transactionProcessingService.credit(transaction); + // Assert assertThat(returnedTransaction).usingRecursiveComparison() - .isEqualTo (TransactionTestUtils.createTransactionUtils(emitterAccountId, receiverAccountId, new BigDecimal("1000"), ERROR, instantDate, metadata)); + .isEqualTo(Transaction.builder() + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(ERROR) + .date(instantDate) + .metadata(new HashMap<>()) + .build()); verify(bankAccountService).findBankAccount(eq(emitterAccountId)); verify(bankAccountService).findBankAccount(eq(receiverAccountId)); verify(transactionStatusService).setStatus(eq(transaction), eq(ERROR), eq(metadata)); @@ -86,23 +138,65 @@ public void credit_shouldThrowNoSuchElementException_whenReceiverAccountIsNotFou @Test public void credit_shouldReturnCompletedTransaction_whenAccountsAreFoundAndCreditTransactionIsValid() { - long emitterBankAccountId = 99L; + // Arrange + long emitterAccountId = 99L; long receiverAccountId = 77L; Money amountOfMoney = Mockito.mock(Money.class); Instant instantDate = Instant.now(); - Transaction transaction = TransactionTestUtils.createTransactionUtils(emitterBankAccountId, receiverAccountId, new BigDecimal("1000"), UNPROCESSED, instantDate, new HashMap<>()); - Transaction outstandingTransaction = TransactionTestUtils.createTransactionUtils(emitterBankAccountId, receiverAccountId, new BigDecimal("1000"), OUTSTANDING, instantDate, new HashMap<>()); - BankAccount emitterBankAccount = BankAccountTestUtils.createBankAccountUtils(emitterBankAccountId, amountOfMoney, transaction); - BankAccount receiverBankAccount = BankAccountTestUtils.createBankAccountUtils(receiverAccountId, amountOfMoney); + Transaction transaction = Transaction.builder() + .id(1L) + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(UNPROCESSED) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); + Transaction outstandingTransaction = Transaction.builder() + .id(1L) + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(UNPROCESSED) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); + BankAccount emitterBankAccount = CheckingBankAccount.builder() + .id(emitterAccountId) + .type(CHECKING) + .balance(amountOfMoney) + .customersId(List.of(99L)) + .issuedTransactions(Set.of(transaction)) + .build(); + BankAccount receiverBankAccount = CheckingBankAccount.builder() + .id(receiverAccountId) + .type(CHECKING) + .balance(amountOfMoney) + .customersId(List.of(99L)) + .build(); Map metadataAfter = Map.of("emitter_amount_before", "1000", "receiver_amount_before", "0", "emitter_amount_after", "0", "receiver_amount_after", "1000"); - Transaction completedTransaction = TransactionTestUtils.createTransactionUtils(emitterBankAccountId, receiverAccountId, new BigDecimal("1000"), COMPLETED, instantDate, metadataAfter); - BankAccount updatedEmitterBankAccount = BankAccountTestUtils.createBankAccountUtils(emitterBankAccountId, amountOfMoney, completedTransaction); + Transaction completedTransaction = Transaction.builder() + .id(1L) + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(COMPLETED) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); + BankAccount updatedEmitterBankAccount = CheckingBankAccount.builder() + .id(emitterAccountId) + .type(CHECKING) + .balance(amountOfMoney) + .customersId(List.of(99L)) + .issuedTransactions(Set.of(completedTransaction)) + .build(); - when(bankAccountService.findBankAccount(emitterBankAccountId)).thenReturn(emitterBankAccount); + when(bankAccountService.findBankAccount(emitterAccountId)).thenReturn(emitterBankAccount); when(bankAccountService.findBankAccount(receiverAccountId)).thenReturn(receiverBankAccount); when(transactionStatusService.setAsOutstanding(transaction)).thenReturn(outstandingTransaction); when(amountOfMoney.getAmount()) @@ -113,36 +207,94 @@ public void credit_shouldReturnCompletedTransaction_whenAccountsAreFoundAndCredi when(transactionStatusService.setStatus(outstandingTransaction, COMPLETED, metadataAfter)).thenReturn(completedTransaction); when(bankAccountService.addTransaction(completedTransaction, emitterBankAccount)).thenReturn(updatedEmitterBankAccount); + // Act Transaction returnedTransaction = transactionProcessingService.credit(transaction); - receiverBankAccount.getBalance().plus(emitterBankAccount.getBalance()); emitterBankAccount.getBalance().minus(emitterBankAccount.getBalance()); + // Assert assertThat(returnedTransaction).usingRecursiveComparison() - .isEqualTo (TransactionTestUtils.createTransactionUtils(emitterBankAccountId, receiverAccountId, new BigDecimal("1000"), COMPLETED, instantDate, metadataAfter)); + .isEqualTo(Transaction.builder() + .id(1L) + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(COMPLETED) + .date(instantDate) + .metadata(new HashMap<>()) + .build()); } @Test public void credit_shouldAddMoneyToTheReceiverAccount_whenAccountsAreFound_fromCreditTransaction() { - long emitterBankAccountId = 99L; + // Arrange + long emitterAccountId = 99L; long receiverAccountId = 77L; Money amountOfMoney = Mockito.mock(Money.class); Instant instantDate = Instant.now(); - Transaction oldTransaction = TransactionTestUtils.createTransactionUtils(emitterBankAccountId, receiverAccountId, new BigDecimal("1000"), UNPROCESSED, instantDate, new HashMap<>()); - BankAccount emitterBankAccount = BankAccountTestUtils.createBankAccountUtils(emitterBankAccountId, amountOfMoney, oldTransaction); - BankAccount receiverBankAccount = BankAccountTestUtils.createBankAccountUtils(receiverAccountId, amountOfMoney); - - Transaction transaction = TransactionTestUtils.createTransactionUtils(emitterBankAccountId, receiverAccountId, new BigDecimal("1000"), UNPROCESSED, instantDate, new HashMap<>()); - Transaction outstandingTransaction = TransactionTestUtils.createTransactionUtils(emitterBankAccountId, receiverAccountId, new BigDecimal("1000"), OUTSTANDING, instantDate, new HashMap<>()); + Transaction oldTransaction = Transaction.builder() + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(UNPROCESSED) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); + BankAccount emitterBankAccount = CheckingBankAccount.builder() + .id(emitterAccountId) + .type(CHECKING) + .balance(amountOfMoney) + .customersId(List.of(99L)) + .issuedTransactions(Set.of(oldTransaction)) + .build(); + BankAccount receiverBankAccount = CheckingBankAccount.builder() + .id(receiverAccountId) + .type(CHECKING) + .balance(amountOfMoney) + .customersId(List.of(99L)) + .build(); + + Transaction transaction = Transaction.builder() + .id(1L) + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(UNPROCESSED) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); + Transaction outstandingTransaction = Transaction.builder() + .id(1L) + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(OUTSTANDING) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); Map metadataAfter = Map.of("emitter_amount_before", "1000", "receiver_amount_before", "0", "emitter_amount_after", "0", "receiver_amount_after", "1000"); - Transaction completedTransaction = TransactionTestUtils.createTransactionUtils(emitterBankAccountId, receiverAccountId, new BigDecimal("1000"), COMPLETED, instantDate, metadataAfter); - BankAccount updatedEmitterBankAccount = BankAccountTestUtils.createBankAccountUtils(emitterBankAccountId, amountOfMoney, completedTransaction); + Transaction completedTransaction = Transaction.builder() + .id(1L) + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(COMPLETED) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); + BankAccount updatedEmitterBankAccount = CheckingBankAccount.builder() + .id(emitterAccountId) + .type(CHECKING) + .balance(amountOfMoney) + .customersId(List.of(99L)) + .issuedTransactions(Set.of(completedTransaction)) + .build(); - when(bankAccountService.findBankAccount(emitterBankAccountId)).thenReturn(emitterBankAccount); + when(bankAccountService.findBankAccount(emitterAccountId)).thenReturn(emitterBankAccount); when(bankAccountService.findBankAccount(receiverAccountId)).thenReturn(receiverBankAccount); when(transactionStatusService.setAsOutstanding(transaction)).thenReturn(outstandingTransaction); when(amountOfMoney.getAmount()) @@ -153,9 +305,11 @@ public void credit_shouldAddMoneyToTheReceiverAccount_whenAccountsAreFound_fromC when(transactionStatusService.setStatus(outstandingTransaction, COMPLETED, metadataAfter)).thenReturn(completedTransaction); when(bankAccountService.addTransaction(completedTransaction, emitterBankAccount)).thenReturn(updatedEmitterBankAccount); + // Act transactionProcessingService.credit(transaction); - verify(bankAccountService).findBankAccount(eq(emitterBankAccountId)); + // Assert + verify(bankAccountService).findBankAccount(eq(emitterAccountId)); verify(bankAccountService).findBankAccount(eq(receiverAccountId)); verify(transactionStatusService).setAsOutstanding(transaction); verify(bankAccountService).transferAmountBetweenAccounts(outstandingTransaction, emitterBankAccount, receiverBankAccount); @@ -168,19 +322,52 @@ public void credit_shouldAddMoneyToTheReceiverAccount_whenAccountsAreFound_fromC @Test public void credit_shouldReturnRefusedTransaction_whenTransferThrowTransactionExceptionException() { - long emitterBankAccountId = 99L; + // Arrange + long emitterAccountId = 99L; long receiverAccountId = 77L; Money amountOfMoney = Mockito.mock(Money.class); Instant instantDate = Instant.now(); - Transaction oldTransaction = TransactionTestUtils.createTransactionUtils(emitterBankAccountId, receiverAccountId, new BigDecimal("-1000"), UNPROCESSED, instantDate, new HashMap<>()); - BankAccount emitterBankAccount = BankAccountTestUtils.createBankAccountUtils(emitterBankAccountId, amountOfMoney, oldTransaction); - BankAccount receiverBankAccount = BankAccountTestUtils.createBankAccountUtils(receiverAccountId, amountOfMoney); - - Transaction transaction = TransactionTestUtils.createTransactionUtils(emitterBankAccountId, receiverAccountId, new BigDecimal("-1000"), UNPROCESSED, instantDate, new HashMap<>()); - Transaction outstandingTransaction = TransactionTestUtils.createTransactionUtils(emitterBankAccountId, receiverAccountId, new BigDecimal("-1000"), OUTSTANDING, instantDate, new HashMap<>()); + Transaction oldTransaction = Transaction.builder() + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("-1000")) + .status(UNPROCESSED) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); + BankAccount emitterBankAccount = CheckingBankAccount.builder() + .id(emitterAccountId) + .type(CHECKING) + .balance(amountOfMoney) + .customersId(List.of(99L)) + .issuedTransactions(Set.of(oldTransaction)) + .build(); + BankAccount receiverBankAccount = CheckingBankAccount.builder() + .id(receiverAccountId) + .type(CHECKING) + .balance(amountOfMoney) + .customersId(List.of(99L)) + .build(); + + Transaction transaction = Transaction.builder() + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("-1000")) + .status(UNPROCESSED) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); + Transaction outstandingTransaction = Transaction.builder() + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("-1000")) + .status(OUTSTANDING) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); Map metadataAfter = Map.of("error", "Credit transaction 1 should have positive value, actual value: -1000"); - when(bankAccountService.findBankAccount(emitterBankAccountId)).thenReturn(emitterBankAccount); + when(bankAccountService.findBankAccount(emitterAccountId)).thenReturn(emitterBankAccount); when(bankAccountService.findBankAccount(receiverAccountId)).thenReturn(receiverBankAccount); when(transactionStatusService.setAsOutstanding(transaction)).thenReturn(outstandingTransaction); when(amountOfMoney.getAmount()) @@ -189,9 +376,11 @@ public void credit_shouldReturnRefusedTransaction_whenTransferThrowTransactionEx doThrow(new TransactionException("Credit transaction 1 should have positive value, actual value: -1000")) .when(bankAccountService).transferAmountBetweenAccounts(outstandingTransaction, emitterBankAccount, receiverBankAccount); + // Act transactionProcessingService.credit(transaction); - verify(bankAccountService).findBankAccount(eq(emitterBankAccountId)); + // Assert + verify(bankAccountService).findBankAccount(eq(emitterAccountId)); verify(bankAccountService).findBankAccount(eq(receiverAccountId)); verify(transactionStatusService).setAsOutstanding(transaction); verify(bankAccountService).transferAmountBetweenAccounts(outstandingTransaction, emitterBankAccount, receiverBankAccount); @@ -201,27 +390,73 @@ public void credit_shouldReturnRefusedTransaction_whenTransferThrowTransactionEx @Test public void credit_shouldReturnErroredTransaction_whenAddTransactionThrowsBankAccountException() { - long emitterBankAccountId = 99L; - long receiverBankAccountId = 77L; + // Arrange + long emitterAccountId = 99L; + long receiverAccountId = 77L; Money amountOfMoney = Mockito.mock(Money.class); Instant instantDate = Instant.now(); - Transaction oldTransaction = TransactionTestUtils.createTransactionUtils(emitterBankAccountId, receiverBankAccountId, new BigDecimal("1000"), UNPROCESSED, instantDate, new HashMap<>()); - BankAccount emitterBankAccount = BankAccountTestUtils.createBankAccountUtils(emitterBankAccountId, amountOfMoney, oldTransaction); - BankAccount receiverBankAccount = BankAccountTestUtils.createBankAccountUtils(receiverBankAccountId, amountOfMoney); - - Transaction transaction = TransactionTestUtils.createTransactionUtils(emitterBankAccountId, receiverBankAccountId, new BigDecimal("1000"), UNPROCESSED, instantDate, new HashMap<>()); - Transaction outstandingTransaction = TransactionTestUtils.createTransactionUtils(emitterBankAccountId, receiverBankAccountId, new BigDecimal("1000"), OUTSTANDING, instantDate, new HashMap<>()); + Transaction oldTransaction = Transaction.builder() + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(UNPROCESSED) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); + BankAccount emitterBankAccount = CheckingBankAccount.builder() + .id(emitterAccountId) + .type(CHECKING) + .balance(amountOfMoney) + .customersId(List.of(99L)) + .issuedTransactions(Set.of(oldTransaction)) + .build(); + BankAccount receiverBankAccount = CheckingBankAccount.builder() + .id(receiverAccountId) + .type(CHECKING) + .balance(amountOfMoney) + .customersId(List.of(99L)) + .build(); + + Transaction transaction = Transaction.builder() + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(UNPROCESSED) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); + Transaction outstandingTransaction = Transaction.builder() + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(OUTSTANDING) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); Map metadataDuringProcess = Map.of("emitter_amount_before", "0", "receiver_amount_before", "0", "emitter_amount_after", "-1000", "receiver_amount_after", "1000"); - Transaction completedTransaction = TransactionTestUtils.createTransactionUtils(emitterBankAccountId, receiverBankAccountId, new BigDecimal("1000"), COMPLETED, instantDate, new HashMap<>()); - BankAccount updatedEmitterBankAccount = BankAccountTestUtils.createBankAccountUtils(emitterBankAccountId, amountOfMoney, completedTransaction); + Transaction completedTransaction = Transaction.builder() + .emitterAccountId(emitterAccountId) + .receiverAccountId(receiverAccountId) + .amount(new BigDecimal("1000")) + .status(COMPLETED) + .date(instantDate) + .metadata(new HashMap<>()) + .build(); + BankAccount updatedEmitterBankAccount = CheckingBankAccount.builder() + .id(emitterAccountId) + .type(CHECKING) + .balance(amountOfMoney) + .customersId(List.of(99L)) + .issuedTransactions(Set.of(completedTransaction)) + .build(); Map metadataAfterError = Map.of("error", "Amount of credit should not be negative"); - when(bankAccountService.findBankAccount(emitterBankAccountId)).thenReturn(emitterBankAccount); - when(bankAccountService.findBankAccount(receiverBankAccountId)).thenReturn(receiverBankAccount); + when(bankAccountService.findBankAccount(emitterAccountId)).thenReturn(emitterBankAccount); + when(bankAccountService.findBankAccount(receiverAccountId)).thenReturn(receiverBankAccount); when(transactionStatusService.setAsOutstanding(transaction)).thenReturn(outstandingTransaction); when(amountOfMoney.getAmount()) .thenReturn(new BigDecimal("0")) @@ -232,10 +467,12 @@ public void credit_shouldReturnErroredTransaction_whenAddTransactionThrowsBankAc when(bankAccountService.addTransaction(completedTransaction, emitterBankAccount)).thenReturn(updatedEmitterBankAccount); doThrow(new BankAccountException("Amount of credit should not be negative")).when(bankAccountService).updateBankAccount(updatedEmitterBankAccount); + // Act transactionProcessingService.credit(transaction); - verify(bankAccountService).findBankAccount(eq(emitterBankAccountId)); - verify(bankAccountService).findBankAccount(eq(receiverBankAccountId)); + // Assert + verify(bankAccountService).findBankAccount(eq(emitterAccountId)); + verify(bankAccountService).findBankAccount(eq(receiverAccountId)); verify(transactionStatusService).setAsOutstanding(transaction); verify(bankAccountService).transferAmountBetweenAccounts(outstandingTransaction, emitterBankAccount, receiverBankAccount); verify(transactionStatusService).setStatus(outstandingTransaction, COMPLETED, metadataDuringProcess); diff --git a/application/src/test/java/com/cdx/bas/application/scheduler/SchedulerTest.java b/application/src/test/java/com/cdx/bas/application/scheduler/SchedulerTest.java index 0a06991c..c055f22b 100644 --- a/application/src/test/java/com/cdx/bas/application/scheduler/SchedulerTest.java +++ b/application/src/test/java/com/cdx/bas/application/scheduler/SchedulerTest.java @@ -1,9 +1,9 @@ package com.cdx.bas.application.scheduler; -import com.cdx.bas.application.bank.transaction.TransactionTestUtils; import com.cdx.bas.domain.bank.transaction.Transaction; import com.cdx.bas.domain.bank.transaction.TransactionPersistencePort; import com.cdx.bas.domain.bank.transaction.TransactionServicePort; +import com.cdx.bas.domain.bank.transaction.type.TransactionType; import io.quarkus.test.InjectMock; import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.TestProfile; @@ -13,12 +13,14 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; +import java.math.BigDecimal; import java.time.Clock; import java.time.Instant; import java.time.ZoneId; import java.util.PriorityQueue; import java.util.Queue; +import static com.cdx.bas.domain.bank.transaction.status.TransactionStatus.UNPROCESSED; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -40,10 +42,13 @@ public class SchedulerTest { @Order(1) @Test public void processQueue_shouldFillTheQueue_whenQueueWasEmpty() { + // Arrange when(transactionRepository.findUnprocessedTransactions()).thenReturn(new PriorityQueue<>()); + // Act scheduler.processQueue(); + // Assert verify(transactionRepository).findUnprocessedTransactions(); verifyNoMoreInteractions(transactionRepository); verifyNoInteractions(transactionService); @@ -52,22 +57,66 @@ public void processQueue_shouldFillTheQueue_whenQueueWasEmpty() { @Order(2) @Test public void processQueue_shouldRunSchedulerProcess_withOrderedQueues_whenQueueIsFilled_withUnprocessedTransactions() { + // Arrange Queue queue = createCreditTransactionsUtils(); when(transactionRepository.findUnprocessedTransactions()).thenReturn(queue); Clock clock; + Transaction fifthTransaction = Transaction.builder() + .id(5L) + .emitterAccountId(99L) + .receiverAccountId(77L) + .amount(new BigDecimal("59")) + .label("Fifth transaction") + .type(TransactionType.CREDIT) + .status(UNPROCESSED) + .date(Instant.MIN) + .build(); + clock = Clock.fixed(Instant.parse("2022-12-06T10:14:00Z"), ZoneId.of("UTC")); + Transaction thirdTransaction = Transaction.builder() + .id(3L) + .emitterAccountId(99L) + .receiverAccountId(77L) + .amount(new BigDecimal("150")) + .label("Third transaction") + .type(TransactionType.CREDIT) + .status(UNPROCESSED) + .date(Instant.now(clock)) + .build(); + clock = Clock.fixed(Instant.parse("2022-12-07T10:14:00Z"), ZoneId.of("UTC")); + Transaction secondTransaction = Transaction.builder() + .id(2L) + .emitterAccountId(99L) + .receiverAccountId(77L) + .amount(new BigDecimal("399")) + .label("Second transaction") + .type(TransactionType.CREDIT) + .status(UNPROCESSED) + .date(Instant.now(clock)) + .build(); + clock = Clock.fixed(Instant.parse("2022-12-07T10:18:00Z"), ZoneId.of("UTC")); + Transaction fourthTransaction = Transaction.builder() + .id(4L) + .emitterAccountId(99L) + .receiverAccountId(77L) + .amount(new BigDecimal("1000")) + .label("Fourth transaction") + .type(TransactionType.CREDIT) + .status(UNPROCESSED) + .date(Instant.now(clock)) + .build(); + + // Act scheduler.processQueue(); - assertThat(queue.peek()).usingRecursiveComparison().isEqualTo (TransactionTestUtils.createTransactionUtils(5L, 59L, Instant.MIN, "Fifth transaction")); + // Assert + assertThat(queue.peek()).usingRecursiveComparison().isEqualTo(fifthTransaction); verify(transactionService).process(queue.poll()); - clock = Clock.fixed(Instant.parse("2022-12-06T10:14:00Z"), ZoneId.of("UTC")); - assertThat(queue.peek()).usingRecursiveComparison().isEqualTo (TransactionTestUtils.createTransactionUtils(3L, 150L, Instant.now(clock), "Third transaction")); + assertThat(queue.peek()).usingRecursiveComparison().isEqualTo(thirdTransaction); verify(transactionService).process(queue.poll()); - clock = Clock.fixed(Instant.parse("2022-12-07T10:14:00Z"), ZoneId.of("UTC")); - assertThat(queue.peek()).usingRecursiveComparison().isEqualTo (TransactionTestUtils.createTransactionUtils(2L, 399L, Instant.now(clock), "Second transaction")); + assertThat(queue.peek()).usingRecursiveComparison().isEqualTo(secondTransaction); verify(transactionService).process(queue.poll()); - clock = Clock.fixed(Instant.parse("2022-12-07T10:18:00Z"), ZoneId.of("UTC")); - assertThat(queue.peek()).usingRecursiveComparison().isEqualTo (TransactionTestUtils.createTransactionUtils(4L, 1000L, Instant.now(clock), "Fourth transaction")); + assertThat(queue.peek()).usingRecursiveComparison().isEqualTo(fourthTransaction); verify(transactionService).process(queue.poll()); verify(transactionRepository).findUnprocessedTransactions(); @@ -75,17 +124,62 @@ public void processQueue_shouldRunSchedulerProcess_withOrderedQueues_whenQueueIs verifyNoMoreInteractions(transactionRepository, transactionService); } - static Queue createCreditTransactionsUtils() { + private static Queue createCreditTransactionsUtils() { Clock clock; Queue queue = new PriorityQueue<>(); - queue.add (TransactionTestUtils.createTransactionUtils(1L, 250L, Instant.MAX, "First transaction")); + queue.add(Transaction.builder() + .id(1L) + .emitterAccountId(99L) + .receiverAccountId(77L) + .amount(new BigDecimal("250")) + .label("First transaction") + .type(TransactionType.CREDIT) + .status(UNPROCESSED) + .date(Instant.MAX) + .build()); clock = Clock.fixed(Instant.parse("2022-12-07T10:14:00Z"), ZoneId.of("UTC")); - queue.add (TransactionTestUtils.createTransactionUtils(2L, 399L, Instant.now(clock), "Second transaction")); + queue.add(Transaction.builder() + .id(2L) + .emitterAccountId(99L) + .receiverAccountId(77L) + .amount(new BigDecimal("399")) + .label("Second transaction") + .type(TransactionType.CREDIT) + .status(UNPROCESSED) + .date(Instant.now(clock)) + .build()); clock = Clock.fixed(Instant.parse("2022-12-06T10:14:00Z"), ZoneId.of("UTC")); - queue.add (TransactionTestUtils.createTransactionUtils(3L, 150L, Instant.now(clock), "Third transaction")); + queue.add(Transaction.builder() + .id(3L) + .emitterAccountId(99L) + .receiverAccountId(77L) + .amount(new BigDecimal("150")) + .label("Third transaction") + .type(TransactionType.CREDIT) + .status(UNPROCESSED) + .date(Instant.now(clock)) + .build()); clock = Clock.fixed(Instant.parse("2022-12-07T10:18:00Z"), ZoneId.of("UTC")); - queue.add (TransactionTestUtils.createTransactionUtils(4L, 1000L, Instant.now(clock), "Fourth transaction")); - queue.add (TransactionTestUtils.createTransactionUtils(5L, 59L, Instant.MIN, "Fifth transaction")); + queue.add(Transaction.builder() + .id(4L) + .emitterAccountId(99L) + .receiverAccountId(77L) + .amount(new BigDecimal("1000")) + .label("Fourth transaction") + .type(TransactionType.CREDIT) + .status(UNPROCESSED) + .date(Instant.now(clock)) + .build()); + queue.add(Transaction.builder() + .id(5L) + .emitterAccountId(99L) + .receiverAccountId(77L) + .amount(new BigDecimal("59")) + .label("Fifth transaction") + .type(TransactionType.CREDIT) + .status(UNPROCESSED) + .date(Instant.MIN) + .build()); return queue; } } \ No newline at end of file diff --git a/domain/src/main/java/com/cdx/bas/domain/bank/account/BankAccount.java b/domain/src/main/java/com/cdx/bas/domain/bank/account/BankAccount.java index f9084116..e5f434ca 100644 --- a/domain/src/main/java/com/cdx/bas/domain/bank/account/BankAccount.java +++ b/domain/src/main/java/com/cdx/bas/domain/bank/account/BankAccount.java @@ -8,9 +8,11 @@ import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; import lombok.*; +import lombok.experimental.SuperBuilder; import java.util.*; @Data +@SuperBuilder @AllArgsConstructor @NoArgsConstructor public abstract class BankAccount { diff --git a/domain/src/main/java/com/cdx/bas/domain/bank/account/BankAccountFactory.java b/domain/src/main/java/com/cdx/bas/domain/bank/account/BankAccountFactory.java index ccfa4a2e..56cd67a3 100644 --- a/domain/src/main/java/com/cdx/bas/domain/bank/account/BankAccountFactory.java +++ b/domain/src/main/java/com/cdx/bas/domain/bank/account/BankAccountFactory.java @@ -1,26 +1,24 @@ package com.cdx.bas.domain.bank.account; -import com.cdx.bas.domain.bank.account.type.AccountType; -import com.cdx.bas.domain.bank.account.BankAccount; import com.cdx.bas.domain.bank.account.checking.CheckingBankAccount; import com.cdx.bas.domain.bank.account.mma.MMABankAccount; import com.cdx.bas.domain.bank.account.saving.SavingBankAccount; +import com.cdx.bas.domain.bank.account.type.AccountType; public class BankAccountFactory { - + private BankAccountFactory() { throw new IllegalStateException("Utility class"); - } - + } + public static BankAccount createBankAccount(AccountType type) { - BankAccount bankAccount = null; if (AccountType.CHECKING.equals(type)) { - bankAccount = new CheckingBankAccount(); + return new CheckingBankAccount(); } else if (AccountType.SAVING.equals(type)) { - bankAccount = new SavingBankAccount(); + return new SavingBankAccount(); } else if (AccountType.MMA.equals(type)) { - bankAccount = new MMABankAccount(); + return new MMABankAccount(); } - return bankAccount; + throw new IllegalArgumentException("Unexpected account type " + type); } } diff --git a/domain/src/main/java/com/cdx/bas/domain/bank/account/checking/CheckingBankAccount.java b/domain/src/main/java/com/cdx/bas/domain/bank/account/checking/CheckingBankAccount.java index 7e95d7d9..afb26221 100644 --- a/domain/src/main/java/com/cdx/bas/domain/bank/account/checking/CheckingBankAccount.java +++ b/domain/src/main/java/com/cdx/bas/domain/bank/account/checking/CheckingBankAccount.java @@ -7,8 +7,10 @@ import com.cdx.bas.domain.money.Money; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; import java.util.List; import java.util.Set; @@ -18,6 +20,7 @@ /** * Checking account (transaction account/current account) */ +@SuperBuilder public class CheckingBankAccount extends BankAccount { @Amount(min=-600, max=100000, message="balance amount must be between -600 and 100000.") diff --git a/domain/src/main/java/com/cdx/bas/domain/bank/account/mma/MMABankAccount.java b/domain/src/main/java/com/cdx/bas/domain/bank/account/mma/MMABankAccount.java index 009a8b3a..74a873f1 100644 --- a/domain/src/main/java/com/cdx/bas/domain/bank/account/mma/MMABankAccount.java +++ b/domain/src/main/java/com/cdx/bas/domain/bank/account/mma/MMABankAccount.java @@ -7,8 +7,10 @@ import com.cdx.bas.domain.money.Money; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; import java.util.List; import java.util.Set; @@ -18,6 +20,7 @@ /** * Money Market Account */ +@SuperBuilder public class MMABankAccount extends BankAccount { @Amount(min=1000, max=250000, message="balance amount must be between 1000 and 250000.") diff --git a/domain/src/main/java/com/cdx/bas/domain/bank/account/saving/SavingBankAccount.java b/domain/src/main/java/com/cdx/bas/domain/bank/account/saving/SavingBankAccount.java index 59866e6d..31d9f68e 100644 --- a/domain/src/main/java/com/cdx/bas/domain/bank/account/saving/SavingBankAccount.java +++ b/domain/src/main/java/com/cdx/bas/domain/bank/account/saving/SavingBankAccount.java @@ -8,10 +8,8 @@ import com.cdx.bas.domain.money.Amount; import com.cdx.bas.domain.money.Money; import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; +import lombok.*; +import lombok.experimental.SuperBuilder; import java.math.BigDecimal; import java.util.List; @@ -22,6 +20,7 @@ /** * Saving Account (French Livret A) */ +@SuperBuilder public class SavingBankAccount extends BankAccount { @Amount(min=1, max=22950, message="balance amount must be between 1 and 22950.") diff --git a/domain/src/test/java/com/cdx/bas/domain/bank/account/BankAccountFactoryTest.java b/domain/src/test/java/com/cdx/bas/domain/bank/account/BankAccountFactoryTest.java index d6a1118f..1e1588ee 100644 --- a/domain/src/test/java/com/cdx/bas/domain/bank/account/BankAccountFactoryTest.java +++ b/domain/src/test/java/com/cdx/bas/domain/bank/account/BankAccountFactoryTest.java @@ -16,29 +16,38 @@ public class BankAccountFactoryTest { @Test public void createBankAccount_shouldReturnNull_whenAccountTypeIsNull() { - BankAccount bankAccount = BankAccountFactory.createBankAccount(null); - - assertThat(bankAccount).isNull(); + // Act + try { + BankAccountFactory.createBankAccount(null); + } catch (IllegalArgumentException exception) { + assertThat(exception.getMessage()).isEqualTo("Unexpected account type null"); + } } @Test public void createBankAccount_shouldReturnCheckingBankAccountInstance_whenAccountTypeIsChecking() { + // Act BankAccount bankAccount = BankAccountFactory.createBankAccount(AccountType.CHECKING); - + + // Assert assertThat(bankAccount).isInstanceOf(CheckingBankAccount.class); } @Test public void createBankAccount_shouldReturnSavingBankAccountInstance_whenAccountTypeIsSaving() { + // Act BankAccount bankAccount = BankAccountFactory.createBankAccount(AccountType.SAVING); - + + // Assert assertThat(bankAccount).isInstanceOf(SavingBankAccount.class); } @Test public void createBankAccount_shouldReturnMMABankAccountInstance_whenAccountTypeIsMMA() { + // Act BankAccount bankAccount = BankAccountFactory.createBankAccount(AccountType.MMA); - + + // Assert assertThat(bankAccount).isInstanceOf(MMABankAccount.class); } } \ No newline at end of file