From 9bea34d7a27158196276fabc304264f7703b0665 Mon Sep 17 00:00:00 2001 From: "VEGA\\m.todorovic" Date: Tue, 9 Aug 2022 15:55:42 +0200 Subject: [PATCH 1/6] Sanitize files. Added gitignore. --- .gitignore | 2 + pom.xml | 12 ++++++ src/main/java/ch/engenius/bank/Account.java | 1 - src/main/java/ch/engenius/bank/Bank.java | 4 +- .../java/ch/engenius/bank/BankRunner.java | 39 +++++++++---------- 5 files changed, 34 insertions(+), 24 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..92322c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea/ +target/ diff --git a/pom.xml b/pom.xml index 2ca15ec..727997d 100644 --- a/pom.xml +++ b/pom.xml @@ -7,6 +7,18 @@ ch.engenius accounts 1.0-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + \ No newline at end of file diff --git a/src/main/java/ch/engenius/bank/Account.java b/src/main/java/ch/engenius/bank/Account.java index b9979cb..4522b61 100644 --- a/src/main/java/ch/engenius/bank/Account.java +++ b/src/main/java/ch/engenius/bank/Account.java @@ -10,7 +10,6 @@ public void withdraw(double amount) { throw new IllegalStateException("not enough credits on account"); } setMoney(money - amount); - } public void deposit(double amount) { diff --git a/src/main/java/ch/engenius/bank/Bank.java b/src/main/java/ch/engenius/bank/Bank.java index 571ebc7..b578644 100644 --- a/src/main/java/ch/engenius/bank/Bank.java +++ b/src/main/java/ch/engenius/bank/Bank.java @@ -3,7 +3,7 @@ import java.util.HashMap; public class Bank { - private HashMap accounts = new HashMap<>(); + private final HashMap accounts = new HashMap<>(); public Account registerAccount(int accountNumber, int amount) { Account account = new Account(); @@ -12,7 +12,7 @@ public Account registerAccount(int accountNumber, int amount) { return account; } - public Account getAccount( int number) { + public Account getAccount(int number) { return accounts.get(number); } } diff --git a/src/main/java/ch/engenius/bank/BankRunner.java b/src/main/java/ch/engenius/bank/BankRunner.java index 10b30fd..6483ddd 100644 --- a/src/main/java/ch/engenius/bank/BankRunner.java +++ b/src/main/java/ch/engenius/bank/BankRunner.java @@ -8,61 +8,58 @@ import java.util.stream.IntStream; public class BankRunner { - private static final ExecutorService executor = Executors.newFixedThreadPool(8); - private final Random random = new Random(43); private final Bank bank = new Bank(); - public static void main(String[] args) { BankRunner runner = new BankRunner(); int accounts = 100; - int defaultDeposit = 1000; - int iterations = 10000; + int defaultDeposit = 1000; + int iterations = 10000; runner.registerAccounts(accounts, defaultDeposit); - runner.sanityCheck(accounts, accounts*defaultDeposit); + runner.sanityCheck(accounts, accounts * defaultDeposit); runner.runBank(iterations, accounts); - runner.sanityCheck(accounts, accounts*defaultDeposit); + runner.sanityCheck(accounts, accounts * defaultDeposit); } private void runBank(int iterations, int maxAccount) { - for (int i =0; i< iterations; i++ ) { - executor.submit( ()-> runRandomOperation(maxAccount)); + for (int i = 0; i < iterations; i++) { + executor.submit(() -> runRandomOperation(maxAccount)); } try { executor.shutdown(); - executor.awaitTermination(100,TimeUnit.SECONDS); + executor.awaitTermination(100, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } } private void runRandomOperation(int maxAccount) { - double transfer = random.nextDouble()*100.0; + double transfer = random.nextDouble() * 100.0; int accountInNumber = random.nextInt(maxAccount); int accountOutNumber = random.nextInt(maxAccount); - Account accIn =bank.getAccount(accountInNumber); - Account accOut =bank.getAccount(accountOutNumber); + Account accIn = bank.getAccount(accountInNumber); + Account accOut = bank.getAccount(accountOutNumber); accIn.deposit(transfer); accOut.withdraw(transfer); } - private void registerAccounts(int number, int defaultMoney) { - for ( int i = 0; i < number; i++) { + private void registerAccounts(int number, int defaultMoney) { + for (int i = 0; i < number; i++) { bank.registerAccount(i, defaultMoney); } } - private void sanityCheck( int accountMaxNumber, int totalExpectedMoney) { + private void sanityCheck(int accountMaxNumber, int totalExpectedMoney) { BigDecimal sum = IntStream.range(0, accountMaxNumber) - .mapToObj( bank::getAccount) - .map ( Account::getMoneyAsBigDecimal) - .reduce( BigDecimal.ZERO, BigDecimal::add); + .mapToObj(bank::getAccount) + .map(Account::getMoneyAsBigDecimal) + .reduce(BigDecimal.ZERO, BigDecimal::add); - if ( sum.intValue() != totalExpectedMoney) { - throw new IllegalStateException("we got "+ sum + " != " + totalExpectedMoney +" (expected)"); + if (sum.intValue() != totalExpectedMoney) { + throw new IllegalStateException("we got " + sum + " != " + totalExpectedMoney + " (expected)"); } System.out.println("sanity check OK"); } From 5dd3185dcd4969bd5ca163cc857bf0aa6380e518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Todorovi=C4=87?= Date: Mon, 15 Aug 2022 13:25:50 +0200 Subject: [PATCH 2/6] Refactoring bad bank. Added custom exceptions, tests and relevant classes. --- pom.xml | 47 +++++++++++- src/main/java/ch/engenius/bank/Account.java | 30 -------- src/main/java/ch/engenius/bank/Bank.java | 18 ----- .../java/ch/engenius/bank/BankRunner.java | 74 +++++++++++-------- .../java/ch/engenius/bank/domain/Account.java | 40 ++++++++++ .../java/ch/engenius/bank/domain/Bank.java | 49 ++++++++++++ .../bank/exception/AccountException.java | 8 ++ .../bank/exception/BankException.java | 8 ++ .../ch/engenius/bank/model/AccountNumber.java | 15 ++++ .../java/ch/engenius/bank/model/Money.java | 25 +++++++ .../ch/engenius/bank/service/BankService.java | 13 ++++ .../java/ch/engenius/bank/AccountTest.java | 39 ++++++++++ src/test/java/ch/engenius/bank/BankTest.java | 35 +++++++++ 13 files changed, 320 insertions(+), 81 deletions(-) delete mode 100644 src/main/java/ch/engenius/bank/Account.java delete mode 100644 src/main/java/ch/engenius/bank/Bank.java create mode 100644 src/main/java/ch/engenius/bank/domain/Account.java create mode 100644 src/main/java/ch/engenius/bank/domain/Bank.java create mode 100644 src/main/java/ch/engenius/bank/exception/AccountException.java create mode 100644 src/main/java/ch/engenius/bank/exception/BankException.java create mode 100644 src/main/java/ch/engenius/bank/model/AccountNumber.java create mode 100644 src/main/java/ch/engenius/bank/model/Money.java create mode 100644 src/main/java/ch/engenius/bank/service/BankService.java create mode 100644 src/test/java/ch/engenius/bank/AccountTest.java create mode 100644 src/test/java/ch/engenius/bank/BankTest.java diff --git a/pom.xml b/pom.xml index 727997d..dc4320c 100644 --- a/pom.xml +++ b/pom.xml @@ -7,6 +7,51 @@ ch.engenius accounts 1.0-SNAPSHOT + + UTF-8 + 1.8 + ${maven.compiler.source} + + + + + org.junit + junit-bom + 5.9.0 + pom + import + + + + + + org.junit.jupiter + junit-jupiter + test + + + org.projectlombok + lombok + 1.18.24 + provided + + + org.slf4j + slf4j-api + 1.7.36 + + + org.slf4j + slf4j-simple + 1.7.36 + + + jakarta.validation + jakarta.validation-api + 3.0.2 + + + @@ -19,6 +64,4 @@ - - \ No newline at end of file diff --git a/src/main/java/ch/engenius/bank/Account.java b/src/main/java/ch/engenius/bank/Account.java deleted file mode 100644 index 4522b61..0000000 --- a/src/main/java/ch/engenius/bank/Account.java +++ /dev/null @@ -1,30 +0,0 @@ -package ch.engenius.bank; - -import java.math.BigDecimal; - -public class Account { - private double money; - - public void withdraw(double amount) { - if ((money - amount) < 0) { - throw new IllegalStateException("not enough credits on account"); - } - setMoney(money - amount); - } - - public void deposit(double amount) { - setMoney(money + amount); - } - - public double getMoney() { - return money; - } - - public void setMoney(double money) { - this.money = money; - } - - public BigDecimal getMoneyAsBigDecimal() { - return BigDecimal.valueOf(money); - } -} diff --git a/src/main/java/ch/engenius/bank/Bank.java b/src/main/java/ch/engenius/bank/Bank.java deleted file mode 100644 index b578644..0000000 --- a/src/main/java/ch/engenius/bank/Bank.java +++ /dev/null @@ -1,18 +0,0 @@ -package ch.engenius.bank; - -import java.util.HashMap; - -public class Bank { - private final HashMap accounts = new HashMap<>(); - - public Account registerAccount(int accountNumber, int amount) { - Account account = new Account(); - account.setMoney(amount); - accounts.put(accountNumber, account); - return account; - } - - public Account getAccount(int number) { - return accounts.get(number); - } -} diff --git a/src/main/java/ch/engenius/bank/BankRunner.java b/src/main/java/ch/engenius/bank/BankRunner.java index 6483ddd..87c5caf 100644 --- a/src/main/java/ch/engenius/bank/BankRunner.java +++ b/src/main/java/ch/engenius/bank/BankRunner.java @@ -1,68 +1,80 @@ package ch.engenius.bank; +import ch.engenius.bank.domain.Account; +import ch.engenius.bank.domain.Bank; +import ch.engenius.bank.model.AccountNumber; +import ch.engenius.bank.model.Money; +import lombok.extern.slf4j.Slf4j; + import java.math.BigDecimal; import java.util.Random; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; import java.util.stream.IntStream; +@Slf4j public class BankRunner { + private static final ExecutorService executor = Executors.newFixedThreadPool(8); private final Random random = new Random(43); - private final Bank bank = new Bank(); + private static final int DEFAULT_DEPOSIT = 1000; + private static final int ITERATIONS = 10000; + private static final int ACCOUNTS = 100; + private final Bank bank; + + public BankRunner() { + ConcurrentMap accounts = new ConcurrentHashMap<>(); + this.bank = new Bank(accounts); + } public static void main(String[] args) { BankRunner runner = new BankRunner(); - int accounts = 100; - int defaultDeposit = 1000; - int iterations = 10000; - runner.registerAccounts(accounts, defaultDeposit); - runner.sanityCheck(accounts, accounts * defaultDeposit); - runner.runBank(iterations, accounts); - runner.sanityCheck(accounts, accounts * defaultDeposit); - + runner.registerAccounts(ACCOUNTS, DEFAULT_DEPOSIT); + runner.sanityCheck(ACCOUNTS, ACCOUNTS * DEFAULT_DEPOSIT); + runner.runBank(ITERATIONS, ACCOUNTS); + runner.sanityCheck(ACCOUNTS, ACCOUNTS * DEFAULT_DEPOSIT); } private void runBank(int iterations, int maxAccount) { for (int i = 0; i < iterations; i++) { - executor.submit(() -> runRandomOperation(maxAccount)); + executor.submit(() -> initiateMoneyTransfer(maxAccount)); } try { executor.shutdown(); - executor.awaitTermination(100, TimeUnit.SECONDS); + if (!executor.awaitTermination(60, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } } catch (InterruptedException e) { - e.printStackTrace(); + log.error("InterruptedException occurred: ", e); + executor.shutdownNow(); + Thread.currentThread().interrupt(); } } - private void runRandomOperation(int maxAccount) { - double transfer = random.nextDouble() * 100.0; - int accountInNumber = random.nextInt(maxAccount); - int accountOutNumber = random.nextInt(maxAccount); - Account accIn = bank.getAccount(accountInNumber); - Account accOut = bank.getAccount(accountOutNumber); - accIn.deposit(transfer); - accOut.withdraw(transfer); + private void initiateMoneyTransfer(int maxAccount) { + Money moneyAmount = new Money(BigDecimal.valueOf(random.nextDouble() * 100.0)); + AccountNumber accountInNumber = new AccountNumber(random.nextInt(maxAccount)); + AccountNumber accountOutNumber = new AccountNumber(random.nextInt(maxAccount)); + + bank.transferMoney(accountOutNumber, accountInNumber, moneyAmount); } - private void registerAccounts(int number, int defaultMoney) { - for (int i = 0; i < number; i++) { - bank.registerAccount(i, defaultMoney); + private void registerAccounts(int numberOfAccounts, int defaultMoney) { + for (int accountNumber = 0; accountNumber < numberOfAccounts; accountNumber++) { + bank.registerAccount(new AccountNumber(accountNumber), new Money(BigDecimal.valueOf(defaultMoney))); } } private void sanityCheck(int accountMaxNumber, int totalExpectedMoney) { BigDecimal sum = IntStream.range(0, accountMaxNumber) - .mapToObj(bank::getAccount) - .map(Account::getMoneyAsBigDecimal) - .reduce(BigDecimal.ZERO, BigDecimal::add); + .mapToObj(a -> bank.getAccount(new AccountNumber(a))) + .map(Account::getMoney) + .reduce(new Money(BigDecimal.ZERO), Money::add).getAmount(); if (sum.intValue() != totalExpectedMoney) { throw new IllegalStateException("we got " + sum + " != " + totalExpectedMoney + " (expected)"); } - System.out.println("sanity check OK"); - } + log.info("Sanity check: OK"); + } } diff --git a/src/main/java/ch/engenius/bank/domain/Account.java b/src/main/java/ch/engenius/bank/domain/Account.java new file mode 100644 index 0000000..8bd2681 --- /dev/null +++ b/src/main/java/ch/engenius/bank/domain/Account.java @@ -0,0 +1,40 @@ +package ch.engenius.bank.domain; + +import ch.engenius.bank.exception.AccountException; +import ch.engenius.bank.model.Money; +import lombok.NonNull; +import lombok.Synchronized; + +import java.math.BigDecimal; + +@NonNull +public class Account { + + private Money money; + + public Account() { + this(new Money(BigDecimal.ZERO)); + } + + public Account(Money money) { + this.money = money; + } + + @Synchronized + public void withdraw(Money amount) throws AccountException { + if (money.getAmount().compareTo(amount.getAmount()) < 0) { + throw new AccountException("Not enough credit on account"); + } + + this.money = money.subtract(amount); + } + + @Synchronized + public void deposit(Money amount) throws AccountException { + this.money = money.add(amount); + } + + public Money getMoney() { + return money; + } +} diff --git a/src/main/java/ch/engenius/bank/domain/Bank.java b/src/main/java/ch/engenius/bank/domain/Bank.java new file mode 100644 index 0000000..a94aa15 --- /dev/null +++ b/src/main/java/ch/engenius/bank/domain/Bank.java @@ -0,0 +1,49 @@ +package ch.engenius.bank.domain; + +import ch.engenius.bank.exception.BankException; +import ch.engenius.bank.model.AccountNumber; +import ch.engenius.bank.model.Money; +import ch.engenius.bank.service.BankService; +import lombok.Synchronized; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +public class Bank implements BankService { + private final ConcurrentMap accounts; + + public Bank() { + this(new ConcurrentHashMap<>()); + } + + public Bank(ConcurrentMap accounts) { + this.accounts = accounts; + } + + @Override + public Account registerAccount(AccountNumber accountNumber, Money amount) { + + if (accounts.containsKey(accountNumber.getNumber())) { + throw new BankException("Account already exists"); + } + + Account account = new Account(amount); + accounts.put(accountNumber.getNumber(), account); + return account; + } + + @Synchronized + public void transferMoney(AccountNumber accountOutNumber, AccountNumber accountInNumber, Money moneyAmount) { + + Account payerAccount = getAccount(accountOutNumber); + Account payeeAccount = getAccount(accountInNumber); + + payerAccount.withdraw(moneyAmount); + payeeAccount.deposit(moneyAmount); + } + + @Override + public Account getAccount(AccountNumber accountNumber) { + return accounts.get(accountNumber.getNumber()); + } +} diff --git a/src/main/java/ch/engenius/bank/exception/AccountException.java b/src/main/java/ch/engenius/bank/exception/AccountException.java new file mode 100644 index 0000000..c5dd980 --- /dev/null +++ b/src/main/java/ch/engenius/bank/exception/AccountException.java @@ -0,0 +1,8 @@ +package ch.engenius.bank.exception; + +public class AccountException extends RuntimeException { + + public AccountException(String message) { + super(message); + } +} diff --git a/src/main/java/ch/engenius/bank/exception/BankException.java b/src/main/java/ch/engenius/bank/exception/BankException.java new file mode 100644 index 0000000..5e84a9e --- /dev/null +++ b/src/main/java/ch/engenius/bank/exception/BankException.java @@ -0,0 +1,8 @@ +package ch.engenius.bank.exception; + +public class BankException extends RuntimeException { + + public BankException(String message) { + super(message); + } +} diff --git a/src/main/java/ch/engenius/bank/model/AccountNumber.java b/src/main/java/ch/engenius/bank/model/AccountNumber.java new file mode 100644 index 0000000..c2a40ac --- /dev/null +++ b/src/main/java/ch/engenius/bank/model/AccountNumber.java @@ -0,0 +1,15 @@ +package ch.engenius.bank.model; + +import jakarta.validation.constraints.PositiveOrZero; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.Value; + +@Value +@RequiredArgsConstructor +public class AccountNumber { + + @NonNull + @PositiveOrZero + private int number; +} diff --git a/src/main/java/ch/engenius/bank/model/Money.java b/src/main/java/ch/engenius/bank/model/Money.java new file mode 100644 index 0000000..6c196a6 --- /dev/null +++ b/src/main/java/ch/engenius/bank/model/Money.java @@ -0,0 +1,25 @@ +package ch.engenius.bank.model; + +import jakarta.validation.constraints.PositiveOrZero; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.Value; + +import java.math.BigDecimal; + +@Value +@RequiredArgsConstructor +public class Money { + + @NonNull + @PositiveOrZero + private BigDecimal amount; + + public Money subtract(Money value) { + return new Money(amount.subtract(value.getAmount())); + } + + public Money add(Money value) { + return new Money(amount.add(value.getAmount())); + } +} diff --git a/src/main/java/ch/engenius/bank/service/BankService.java b/src/main/java/ch/engenius/bank/service/BankService.java new file mode 100644 index 0000000..ceed3d9 --- /dev/null +++ b/src/main/java/ch/engenius/bank/service/BankService.java @@ -0,0 +1,13 @@ +package ch.engenius.bank.service; + +import ch.engenius.bank.domain.Account; +import ch.engenius.bank.exception.BankException; +import ch.engenius.bank.model.AccountNumber; +import ch.engenius.bank.model.Money; + +public interface BankService { + + Account registerAccount(AccountNumber accountNumber, Money amount) throws BankException; + + Account getAccount(AccountNumber accountNumber) throws BankException; +} diff --git a/src/test/java/ch/engenius/bank/AccountTest.java b/src/test/java/ch/engenius/bank/AccountTest.java new file mode 100644 index 0000000..a455f8f --- /dev/null +++ b/src/test/java/ch/engenius/bank/AccountTest.java @@ -0,0 +1,39 @@ +package ch.engenius.bank; + +import ch.engenius.bank.domain.Account; +import ch.engenius.bank.exception.AccountException; +import ch.engenius.bank.model.Money; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class AccountTest { + private Account account; + private final Money initialAccountMoney = new Money(BigDecimal.valueOf(100)); + + @BeforeEach + public void setUp() { + account = new Account(initialAccountMoney); + } + + @Test + void shouldWithdrawMoney_whenAmountProvided() { + final BigDecimal withdrawAmount = BigDecimal.valueOf(10); + Money withdrawMoney = new Money(withdrawAmount); + + account.withdraw(withdrawMoney); + assertEquals(initialAccountMoney.getAmount().subtract(withdrawMoney.getAmount()), account.getMoney().getAmount()); + } + + @Test + void shouldDepositMoney_whenAmountProvided() { + final BigDecimal depositAmount = BigDecimal.valueOf(10); + Money depositMoney = new Money(depositAmount); + + account.deposit(depositMoney); + assertEquals(initialAccountMoney.getAmount().add(depositMoney.getAmount()), account.getMoney().getAmount()); + } +} \ No newline at end of file diff --git a/src/test/java/ch/engenius/bank/BankTest.java b/src/test/java/ch/engenius/bank/BankTest.java new file mode 100644 index 0000000..6744a46 --- /dev/null +++ b/src/test/java/ch/engenius/bank/BankTest.java @@ -0,0 +1,35 @@ +package ch.engenius.bank; + +import ch.engenius.bank.domain.Account; +import ch.engenius.bank.domain.Bank; +import ch.engenius.bank.exception.BankException; +import ch.engenius.bank.model.AccountNumber; +import ch.engenius.bank.model.Money; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class BankTest { + private Bank bank; + public static final int ACCOUNT_NUMBER = 1; + private final BigDecimal initialAccountMoney = BigDecimal.valueOf(100); + + @BeforeEach + public void setUp() { + bank = new Bank(); + } + + @Test + void shouldRegisterAccount_whenAccountNumberAndMoneyProvided() throws BankException { + AccountNumber accountNumber = new AccountNumber(ACCOUNT_NUMBER); + Money money = new Money(initialAccountMoney); + + bank.registerAccount(accountNumber, money); + + Account account = bank.getAccount(accountNumber); + assertNotNull(account); + } +} \ No newline at end of file From f6b776787bec881f15148f2fe26bb18136daf2a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Todorovi=C4=87?= Date: Mon, 15 Aug 2022 13:51:51 +0200 Subject: [PATCH 3/6] Removed unnecessary import. --- src/test/java/ch/engenius/bank/AccountTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/ch/engenius/bank/AccountTest.java b/src/test/java/ch/engenius/bank/AccountTest.java index a455f8f..0e35d2b 100644 --- a/src/test/java/ch/engenius/bank/AccountTest.java +++ b/src/test/java/ch/engenius/bank/AccountTest.java @@ -1,7 +1,6 @@ package ch.engenius.bank; import ch.engenius.bank.domain.Account; -import ch.engenius.bank.exception.AccountException; import ch.engenius.bank.model.Money; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; From f9893c0a54f162677b16d548e10a37ce26c37e32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Todorovi=C4=87?= Date: Mon, 15 Aug 2022 16:07:52 +0200 Subject: [PATCH 4/6] Code cleanup and added missing transferMoney test. --- .../java/ch/engenius/bank/domain/Account.java | 4 +-- src/test/java/ch/engenius/bank/BankTest.java | 29 ++++++++++++++++--- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/main/java/ch/engenius/bank/domain/Account.java b/src/main/java/ch/engenius/bank/domain/Account.java index 8bd2681..2c9d698 100644 --- a/src/main/java/ch/engenius/bank/domain/Account.java +++ b/src/main/java/ch/engenius/bank/domain/Account.java @@ -21,7 +21,7 @@ public Account(Money money) { } @Synchronized - public void withdraw(Money amount) throws AccountException { + public void withdraw(Money amount) { if (money.getAmount().compareTo(amount.getAmount()) < 0) { throw new AccountException("Not enough credit on account"); } @@ -30,7 +30,7 @@ public void withdraw(Money amount) throws AccountException { } @Synchronized - public void deposit(Money amount) throws AccountException { + public void deposit(Money amount) { this.money = money.add(amount); } diff --git a/src/test/java/ch/engenius/bank/BankTest.java b/src/test/java/ch/engenius/bank/BankTest.java index 6744a46..3300e45 100644 --- a/src/test/java/ch/engenius/bank/BankTest.java +++ b/src/test/java/ch/engenius/bank/BankTest.java @@ -2,7 +2,6 @@ import ch.engenius.bank.domain.Account; import ch.engenius.bank.domain.Bank; -import ch.engenius.bank.exception.BankException; import ch.engenius.bank.model.AccountNumber; import ch.engenius.bank.model.Money; import org.junit.jupiter.api.BeforeEach; @@ -10,11 +9,11 @@ import java.math.BigDecimal; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; class BankTest { private Bank bank; - public static final int ACCOUNT_NUMBER = 1; private final BigDecimal initialAccountMoney = BigDecimal.valueOf(100); @BeforeEach @@ -23,13 +22,35 @@ public void setUp() { } @Test - void shouldRegisterAccount_whenAccountNumberAndMoneyProvided() throws BankException { - AccountNumber accountNumber = new AccountNumber(ACCOUNT_NUMBER); + void shouldRegisterAccount_whenAccountNumberAndMoneyProvided() { Money money = new Money(initialAccountMoney); + AccountNumber accountNumber = new AccountNumber(1); bank.registerAccount(accountNumber, money); Account account = bank.getAccount(accountNumber); assertNotNull(account); } + + @Test + void shouldTransferMoney_whenPayerAccountAndPayeeAccountAndMoneyProvided() { + Money initialMoney = new Money(initialAccountMoney); + Money transferMoney = new Money(BigDecimal.valueOf(20)); + + AccountNumber payerAccountNumber = new AccountNumber(1); + bank.registerAccount(payerAccountNumber, initialMoney); + + AccountNumber payeeAccountNumber = new AccountNumber(2); + bank.registerAccount(payeeAccountNumber, initialMoney); + + bank.transferMoney(payerAccountNumber, payeeAccountNumber, transferMoney); + + Account payer = bank.getAccount(payerAccountNumber); + Account payee = bank.getAccount(payeeAccountNumber); + + assertEquals(payer.getMoney().getAmount(), + initialMoney.getAmount().subtract(transferMoney.getAmount())); + assertEquals(payee.getMoney().getAmount(), + initialMoney.getAmount().add(transferMoney.getAmount())); + } } \ No newline at end of file From d1f686282f11fb3ee01865ad3196fa67c7554286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Todorovi=C4=87?= Date: Mon, 15 Aug 2022 17:22:10 +0200 Subject: [PATCH 5/6] Added additional tests and BankTest class code cleanup. --- src/test/java/ch/engenius/bank/BankTest.java | 28 ++++++++++------- .../ch/engenius/bank/model/MoneyTest.java | 30 +++++++++++++++++++ 2 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 src/test/java/ch/engenius/bank/model/MoneyTest.java diff --git a/src/test/java/ch/engenius/bank/BankTest.java b/src/test/java/ch/engenius/bank/BankTest.java index 3300e45..3621d43 100644 --- a/src/test/java/ch/engenius/bank/BankTest.java +++ b/src/test/java/ch/engenius/bank/BankTest.java @@ -14,34 +14,30 @@ class BankTest { private Bank bank; - private final BigDecimal initialAccountMoney = BigDecimal.valueOf(100); + private Money initialAccountMoney; @BeforeEach public void setUp() { bank = new Bank(); + initialAccountMoney = new Money(BigDecimal.valueOf(100)); } @Test void shouldRegisterAccount_whenAccountNumberAndMoneyProvided() { - Money money = new Money(initialAccountMoney); AccountNumber accountNumber = new AccountNumber(1); - bank.registerAccount(accountNumber, money); - - Account account = bank.getAccount(accountNumber); - assertNotNull(account); + assertNotNull(bank.registerAccount(accountNumber, initialAccountMoney)); } @Test void shouldTransferMoney_whenPayerAccountAndPayeeAccountAndMoneyProvided() { - Money initialMoney = new Money(initialAccountMoney); Money transferMoney = new Money(BigDecimal.valueOf(20)); AccountNumber payerAccountNumber = new AccountNumber(1); - bank.registerAccount(payerAccountNumber, initialMoney); + bank.registerAccount(payerAccountNumber, initialAccountMoney); AccountNumber payeeAccountNumber = new AccountNumber(2); - bank.registerAccount(payeeAccountNumber, initialMoney); + bank.registerAccount(payeeAccountNumber, initialAccountMoney); bank.transferMoney(payerAccountNumber, payeeAccountNumber, transferMoney); @@ -49,8 +45,18 @@ void shouldTransferMoney_whenPayerAccountAndPayeeAccountAndMoneyProvided() { Account payee = bank.getAccount(payeeAccountNumber); assertEquals(payer.getMoney().getAmount(), - initialMoney.getAmount().subtract(transferMoney.getAmount())); + initialAccountMoney.getAmount().subtract(transferMoney.getAmount())); assertEquals(payee.getMoney().getAmount(), - initialMoney.getAmount().add(transferMoney.getAmount())); + initialAccountMoney.getAmount().add(transferMoney.getAmount())); + } + + @Test + void shouldGetAccount_whenAccountNumberProvided() { + AccountNumber accountNumber = new AccountNumber(1); + bank.registerAccount(accountNumber, initialAccountMoney); + + Account account = bank.getAccount(accountNumber); + + assertNotNull(account); } } \ No newline at end of file diff --git a/src/test/java/ch/engenius/bank/model/MoneyTest.java b/src/test/java/ch/engenius/bank/model/MoneyTest.java new file mode 100644 index 0000000..865bf7d --- /dev/null +++ b/src/test/java/ch/engenius/bank/model/MoneyTest.java @@ -0,0 +1,30 @@ +package ch.engenius.bank.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class MoneyTest { + + private Money initialMoney; + private Money amount; + + @BeforeEach + public void setUp() { + initialMoney = new Money(BigDecimal.valueOf(100)); + amount = new Money(BigDecimal.valueOf(30)); + } + + @Test + void shouldSubtract_whenAmountProvided() { + assertEquals(initialMoney.subtract(amount), new Money(BigDecimal.valueOf(70))); + } + + @Test + void shouldAdd_whenAmountProvided() { + assertEquals(initialMoney.add(amount), new Money(BigDecimal.valueOf(130))); + } +} \ No newline at end of file From 40c2f70f6619c4625b0f125a456a526552ceb4c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Todorovi=C4=87?= Date: Tue, 16 Aug 2022 11:18:55 +0200 Subject: [PATCH 6/6] Updated Account with AccountNumber. Changed type of keys for ConcurrentMap. Updated AccountTest. Added some additional checks. --- src/main/java/ch/engenius/bank/BankRunner.java | 7 +++---- .../java/ch/engenius/bank/domain/Account.java | 16 ++++++++-------- src/main/java/ch/engenius/bank/domain/Bank.java | 17 +++++++++-------- src/test/java/ch/engenius/bank/AccountTest.java | 4 +++- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/main/java/ch/engenius/bank/BankRunner.java b/src/main/java/ch/engenius/bank/BankRunner.java index 87c5caf..2f49e43 100644 --- a/src/main/java/ch/engenius/bank/BankRunner.java +++ b/src/main/java/ch/engenius/bank/BankRunner.java @@ -13,16 +13,15 @@ @Slf4j public class BankRunner { - - private static final ExecutorService executor = Executors.newFixedThreadPool(8); - private final Random random = new Random(43); private static final int DEFAULT_DEPOSIT = 1000; private static final int ITERATIONS = 10000; private static final int ACCOUNTS = 100; + private static final ExecutorService executor = Executors.newFixedThreadPool(8); + private final Random random = new Random(43); private final Bank bank; public BankRunner() { - ConcurrentMap accounts = new ConcurrentHashMap<>(); + ConcurrentMap accounts = new ConcurrentHashMap<>(); this.bank = new Bank(accounts); } diff --git a/src/main/java/ch/engenius/bank/domain/Account.java b/src/main/java/ch/engenius/bank/domain/Account.java index 2c9d698..6917770 100644 --- a/src/main/java/ch/engenius/bank/domain/Account.java +++ b/src/main/java/ch/engenius/bank/domain/Account.java @@ -1,22 +1,18 @@ package ch.engenius.bank.domain; import ch.engenius.bank.exception.AccountException; +import ch.engenius.bank.model.AccountNumber; import ch.engenius.bank.model.Money; import lombok.NonNull; import lombok.Synchronized; -import java.math.BigDecimal; - @NonNull public class Account { - private Money money; + private final AccountNumber accountNumber; - public Account() { - this(new Money(BigDecimal.ZERO)); - } - - public Account(Money money) { + public Account(AccountNumber accountNumber, Money money) { + this.accountNumber = accountNumber; this.money = money; } @@ -37,4 +33,8 @@ public void deposit(Money amount) { public Money getMoney() { return money; } + + public AccountNumber getAccountNumber() { + return accountNumber; + } } diff --git a/src/main/java/ch/engenius/bank/domain/Bank.java b/src/main/java/ch/engenius/bank/domain/Bank.java index a94aa15..d89280d 100644 --- a/src/main/java/ch/engenius/bank/domain/Bank.java +++ b/src/main/java/ch/engenius/bank/domain/Bank.java @@ -10,31 +10,29 @@ import java.util.concurrent.ConcurrentMap; public class Bank implements BankService { - private final ConcurrentMap accounts; + private final ConcurrentMap accounts; public Bank() { this(new ConcurrentHashMap<>()); } - public Bank(ConcurrentMap accounts) { + public Bank(ConcurrentMap accounts) { this.accounts = accounts; } @Override public Account registerAccount(AccountNumber accountNumber, Money amount) { - - if (accounts.containsKey(accountNumber.getNumber())) { + if (accounts.containsKey(accountNumber)) { throw new BankException("Account already exists"); } - Account account = new Account(amount); - accounts.put(accountNumber.getNumber(), account); + Account account = new Account(accountNumber, amount); + accounts.put(accountNumber, account); return account; } @Synchronized public void transferMoney(AccountNumber accountOutNumber, AccountNumber accountInNumber, Money moneyAmount) { - Account payerAccount = getAccount(accountOutNumber); Account payeeAccount = getAccount(accountInNumber); @@ -44,6 +42,9 @@ public void transferMoney(AccountNumber accountOutNumber, AccountNumber accountI @Override public Account getAccount(AccountNumber accountNumber) { - return accounts.get(accountNumber.getNumber()); + if (accounts.get(accountNumber) == null) { + throw new BankException("Account not found"); + } + return accounts.get(accountNumber); } } diff --git a/src/test/java/ch/engenius/bank/AccountTest.java b/src/test/java/ch/engenius/bank/AccountTest.java index 0e35d2b..655c624 100644 --- a/src/test/java/ch/engenius/bank/AccountTest.java +++ b/src/test/java/ch/engenius/bank/AccountTest.java @@ -1,6 +1,7 @@ package ch.engenius.bank; import ch.engenius.bank.domain.Account; +import ch.engenius.bank.model.AccountNumber; import ch.engenius.bank.model.Money; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -12,10 +13,11 @@ class AccountTest { private Account account; private final Money initialAccountMoney = new Money(BigDecimal.valueOf(100)); + private final AccountNumber defaultAccountNumber = new AccountNumber(1); @BeforeEach public void setUp() { - account = new Account(initialAccountMoney); + account = new Account(defaultAccountNumber, initialAccountMoney); } @Test