From e95fe430df5fb8bea45b22fe8a90c6cbb913f06b Mon Sep 17 00:00:00 2001 From: Berk Yavuz <berk.yavuz@eteration.com> Date: Fri, 19 Jul 2019 15:22:52 +0300 Subject: [PATCH] setup solution readme fix --- .gitignore | 11 + README.md | 215 ++++++++++-------- img/testResult.jpg | Bin 0 -> 29298 bytes setup/banking/_classpath.xml | 39 ++++ setup/banking/_project.xml | 37 +++ setup/banking/pom.xml | 36 +++ .../InsufficientBalanceException.java | 12 + .../com/eteration/banking/model/Account.java | 89 ++++++++ .../banking/model/DepositTransaction.java | 11 + .../eteration/banking/model/Transaction.java | 34 +++ .../banking/model/WithdrawalTransaction.java | 12 + .../com/eteration/banking/util/DateUtil.java | 12 + setup/banking/src/main/webapp/WEB-INF/web.xml | 12 + .../banking/tests/TestBankAccount.java | 77 +++++++ solution/banking/_classpath.xml | 39 ++++ solution/banking/_project.xml | 37 +++ solution/banking/pom.xml | 43 ++++ .../eteration/banking/dao/CurrencyDAO.java | 5 + .../InsufficientBalanceException.java | 12 + .../com/eteration/banking/model/Account.java | 104 +++++++++ .../banking/model/DepositTransaction.java | 11 + .../eteration/banking/model/Transaction.java | 34 +++ .../banking/model/WithdrawalTransaction.java | 12 + .../com/eteration/banking/util/DateUtil.java | 12 + .../banking/src/main/webapp/WEB-INF/web.xml | 12 + .../banking/tests/TestBankAccount.java | 97 ++++++++ 26 files changed, 924 insertions(+), 91 deletions(-) create mode 100644 .gitignore create mode 100644 img/testResult.jpg create mode 100644 setup/banking/_classpath.xml create mode 100644 setup/banking/_project.xml create mode 100644 setup/banking/pom.xml create mode 100644 setup/banking/src/main/java/com/eteration/banking/exception/InsufficientBalanceException.java create mode 100644 setup/banking/src/main/java/com/eteration/banking/model/Account.java create mode 100644 setup/banking/src/main/java/com/eteration/banking/model/DepositTransaction.java create mode 100644 setup/banking/src/main/java/com/eteration/banking/model/Transaction.java create mode 100644 setup/banking/src/main/java/com/eteration/banking/model/WithdrawalTransaction.java create mode 100644 setup/banking/src/main/java/com/eteration/banking/util/DateUtil.java create mode 100644 setup/banking/src/main/webapp/WEB-INF/web.xml create mode 100644 setup/banking/src/test/java/com/eteration/banking/tests/TestBankAccount.java create mode 100644 solution/banking/_classpath.xml create mode 100644 solution/banking/_project.xml create mode 100644 solution/banking/pom.xml create mode 100644 solution/banking/src/main/java/com/eteration/banking/dao/CurrencyDAO.java create mode 100644 solution/banking/src/main/java/com/eteration/banking/exception/InsufficientBalanceException.java create mode 100644 solution/banking/src/main/java/com/eteration/banking/model/Account.java create mode 100644 solution/banking/src/main/java/com/eteration/banking/model/DepositTransaction.java create mode 100644 solution/banking/src/main/java/com/eteration/banking/model/Transaction.java create mode 100644 solution/banking/src/main/java/com/eteration/banking/model/WithdrawalTransaction.java create mode 100644 solution/banking/src/main/java/com/eteration/banking/util/DateUtil.java create mode 100644 solution/banking/src/main/webapp/WEB-INF/web.xml create mode 100644 solution/banking/src/test/java/com/eteration/banking/tests/TestBankAccount.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4f8211f --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +.settings +.project +.history +.classpath +target +.DS_Store +.flattened-pom.xml +.gradle +bin +build +/target \ No newline at end of file diff --git a/README.md b/README.md index 70e83fa..e65bbd7 100644 --- a/README.md +++ b/README.md @@ -25,18 +25,6 @@ The main idea of mock is splitting test method into three parts: setting, execut 2. To use Mockito framework, open `pom.xml` file and add following code inside the dependicies. -```xml -<dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>2.10.0</version> - <scope>test</scope> -</dependency> - -``` - -3. Open `pom.xml` file and change the version of mockito to 2.23.4 - ```xml <dependency> <groupId>org.mockito</groupId> @@ -46,109 +34,154 @@ The main idea of mock is splitting test method into three parts: setting, execut </dependency> ``` -4. After theese you will have a project structre like that +3. After theese you will have a project structre like that ``` -├───.settings -├───src -│ ├───main -│ │ ├───java -│ │ │ └───com -│ │ │ └───eteration -│ │ │ └───banking -│ │ │ ├───exception -│ │ │ ├───model -│ │ │ └───util -│ │ ├───resources -│ │ └───webapp -│ │ └───WEB-INF -│ └───test -│ ├───java -│ │ └───com -│ │ └───eteration -│ │ └───banking -│ │ └───tests -│ └───resources -└───target - ├───classes - │ └───com - │ └───eteration - │ └───banking - │ ├───exception - │ ├───model - │ └───util - ├───m2e-wtp - │ └───web-resources - │ └───META-INF - │ └───maven - │ └───banking.app - │ └───banking - └───test-classes - └───com - └───eteration - └───banking - └───tests +. +├── _classpath.xml +├── pom.xml +├── _project.xml +├── src +│  ├── main +│  │  ├── java +│  │  │  └── com +│  │  │  └── eteration +│  │  │  └── banking +│  │  │  ├── exception +│  │  │  │  └── InsufficientBalanceException.java +│  │  │  ├── model +│  │  │  │  ├── Account.java +│  │  │  │  ├── DepositTransaction.java +│  │  │  │  ├── Transaction.java +│  │  │  │  └── WithdrawalTransaction.java +│  │  │  └── util +│  │  │  └── DateUtil.java +│  │  └── webapp +│  │  └── WEB-INF +│  │  └── web.xml +│  └── test +│  └── java +│  └── com +│  └── eteration +│  └── banking +│  └── tests +│  └── TestBankAccount.java +└── target + ├── classes + │  └── com + │  └── eteration + │  └── banking + │  ├── exception + │  │  └── InsufficientBalanceException.class + │  ├── model + │  │  ├── Account.class + │  │  ├── DepositTransaction.class + │  │  ├── Transaction.class + │  │  └── WithdrawalTransaction.class + │  └── util + │  └── DateUtil.class + ├── m2e-wtp + │  └── web-resources + │  └── META-INF + │  ├── MANIFEST.MF + │  └── maven + │  └── banking.app + │  └── banking + │  ├── pom.properties + │  └── pom.xml + └── test-classes + └── com + └── eteration + └── banking + └── tests + └── TestBankAccount.class ``` -5. According to Test Driven Development approach, we will write a test first. We create an account with a 1000 balance in type of TL and then convert this balance to `USD` and `EURO`. Here is the required method: + +4. The balance should be changed to other curreny units. Because of that, we will need class of DAO. Lets create `CurrencyDAO` interface inside `com.eteration.banking.dao` package. ```java +public interface CurrencyDAO { + public double getTLRate(String currencyCode); +} +``` -@Test -public void testCurrencyConverter() { - Account account = new Account("Canan","1234"); - CurrencyDAO mockedCurrencyDAO = mock(CurrencyDAO.class); - account.post(new DepositTransaction(1000)); - when(mockedCurrencyDAO.getTLRate("USD")).thenReturn(5.34); - when(mockedCurrencyDAO.getTLRate("EUR")).thenReturn(6.06); - account.setCurrencyDAO(mockedCurrencyDAO); - - assertEquals(187.26,account.convertBalance("USD"),0);; - assertEquals(165.01,account.convertBalance("EUR"),0); - verify(mockedCurrencyDAO).getTLRate("EUR"); - verify(mockedCurrencyDAO).getTLRate("USD"); +5. Add the "CurrencyDAO" dependency to the "Account" class. + +```java +private CurrencyDAO currencyDAO; + + public CurrencyDAO getCurrencyDAO() { + return currencyDAO; + } + + public void setCurrencyDAO(CurrencyDAO currencyDAO) { + this.currencyDAO = currencyDAO; + } + +``` + +6. Add the method to convert the balance amount to other currencies in the "Account" class. +```java +public double convertBalance(String currencyCode){ + double rate=getCurrencyDAO().getTLRate(currencyCode); + return (int)(getBalance()/rate*100)/100.0; } ``` -If we want to test this method, test will fail. Because we do not create an interface and its necessaries methods yet. So now we will create an interface and implement it onto Account.java under `src\main\java\com\eteration\banking\model` +7. Add static import to `TestBankAccount.java`. -6. Add a new CurrencyDAO folder under the `src/main/java/com/eteration/banking` and create CurrencyDAO interface into it.Here is the CurrencyDAO: +``` java +import static org.mockito.Mockito.*; +``` -```java -package com.eteration.banking.dao; +8. Create an account with has a balance equals of 1000. -public interface CurrencyDAO { - public double getTLRate(String currencyCode); -} +```java +Account account = new Account("Canan","1234"); +CurrencyDAO mockedCurrencyDAO = mock(CurrencyDAO.class); +account.post(new DepositTransaction(1000)); ``` ->After adding interface we have to do some changes on the Account.java under `src/main/java/com/eteration/banking/model`. +9. Let's record Mock Object. ->Firstly declare `currencyDAO` and to use it add getter and setter methods. -```java -private CurrencyDAO currencyDAO; +```java +when(mockedCurrencyDAO.getTLRate("USD")).thenReturn(5.34); +when(mockedCurrencyDAO.getTLRate("EUR")).thenReturn(6.06); +account.setCurrencyDAO(mockedCurrencyDAO); +``` +10. Add the assertions and be sure about the `CurrenyDAO` is called twice. -public CurrencyDAO getCurrencyDAO() { - return currencyDAO; -} - -public void setCurrencyDAO(CurrencyDAO currencyDAO) { - this.currencyDAO = currencyDAO; -} +```java +assertEquals(187.26,account.convertBalance("USD"));; +assertEquals(165.01,account.convertBalance("EUR")); +verify(mockedCurrencyDAO).getTLRate("EUR"); +verify(mockedCurrencyDAO).getTLRate("USD"); ``` ->Before testing step we have to add one more methods to convert its balance to the intended currency. + +11. After theese steps, the method should like below ```java -public double convertBalance(String currencyCode){ - double rate=getCurrencyDAO().getTLRate(currencyCode); - return (int)(getBalance()/rate*100)/100.0; +@Test +public void testCurrencyConverter() { + Account account = new Account("Canan","1234"); + CurrencyDAO mockedCurrencyDAO = mock(CurrencyDAO.class); + account.post(new DepositTransaction(1000)); + when(mockedCurrencyDAO.getTLRate("USD")).thenReturn(5.34); + when(mockedCurrencyDAO.getTLRate("EUR")).thenReturn(6.06); + account.setCurrencyDAO(mockedCurrencyDAO); + + assertEquals(187.26,account.convertBalance("USD"),0);; + assertEquals(165.01,account.convertBalance("EUR"),0); + verify(mockedCurrencyDAO).getTLRate("EUR"); + verify(mockedCurrencyDAO).getTLRate("USD"); } ``` -7. If we run the test now, test will pass successfully +12. If we run the test now, test will pass successfully - + -8. In the `solution` folder, there is complete project includes several unit tests similar to test we created. To exercise you can check if all the tests work. If some of these tests fails, write the required functions as stated by Test Driven Development method. \ No newline at end of file +--- \ No newline at end of file diff --git a/img/testResult.jpg b/img/testResult.jpg new file mode 100644 index 0000000000000000000000000000000000000000..382fb080b848d14ea232a02724adca6962d12706 GIT binary patch literal 29298 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 aSc@)mJepeN|5a%DPr>E?_mSYAh5rD;{Qh77 literal 0 HcmV?d00001 diff --git a/setup/banking/_classpath.xml b/setup/banking/_classpath.xml new file mode 100644 index 0000000..9fc63d3 --- /dev/null +++ b/setup/banking/_classpath.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" output="target/classes" path="src/main/java"> + <attributes> + <attribute name="optional" value="true"/> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="src" output="target/test-classes" path="src/test/java"> + <attributes> + <attribute name="optional" value="true"/> + <attribute name="maven.pomderived" value="true"/> + <attribute name="test" value="true"/> + </attributes> + </classpathentry> + <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + <attribute name="test" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + <attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/> + </attributes> + </classpathentry> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="output" path="target/classes"/> +</classpath> diff --git a/setup/banking/_project.xml b/setup/banking/_project.xml new file mode 100644 index 0000000..4ba4a3e --- /dev/null +++ b/setup/banking/_project.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>banking</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.wst.common.project.facet.core.builder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.wst.validation.validationbuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.m2e.core.maven2Builder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jem.workbench.JavaEMFNature</nature> + <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + <nature>org.eclipse.m2e.core.maven2Nature</nature> + <nature>org.eclipse.wst.common.project.facet.core.nature</nature> + <nature>org.eclipse.wst.jsdt.core.jsNature</nature> + </natures> +</projectDescription> diff --git a/setup/banking/pom.xml b/setup/banking/pom.xml new file mode 100644 index 0000000..5a5fdb8 --- /dev/null +++ b/setup/banking/pom.xml @@ -0,0 +1,36 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>banking.app</groupId> + <artifactId>banking</artifactId> + <version>0.0.1-SNAPSHOT</version> + <packaging>war</packaging> + <dependencies> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-api</artifactId> + <version>5.5.0</version> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + <version>5.5.0</version> + <scope>test</scope> + </dependency> + + </dependencies> + <build> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <groupId>org.apache.maven.plugins</groupId> + <configuration> + <source>1.8</source> + <target>1.8</target> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/setup/banking/src/main/java/com/eteration/banking/exception/InsufficientBalanceException.java b/setup/banking/src/main/java/com/eteration/banking/exception/InsufficientBalanceException.java new file mode 100644 index 0000000..38542cc --- /dev/null +++ b/setup/banking/src/main/java/com/eteration/banking/exception/InsufficientBalanceException.java @@ -0,0 +1,12 @@ +package com.eteration.banking.exception; + +public class InsufficientBalanceException extends Exception{ + public InsufficientBalanceException() { + super(); + } + + public InsufficientBalanceException(String message) { + super(message); + } + +} diff --git a/setup/banking/src/main/java/com/eteration/banking/model/Account.java b/setup/banking/src/main/java/com/eteration/banking/model/Account.java new file mode 100644 index 0000000..654287b --- /dev/null +++ b/setup/banking/src/main/java/com/eteration/banking/model/Account.java @@ -0,0 +1,89 @@ +package com.eteration.banking.model; + +import java.util.ArrayList; +import java.util.List; + +import com.eteration.banking.exception.InsufficientBalanceException; +import com.eteration.banking.util.DateUtil; + +public class Account { + private String accountNumber; + private String owner; + private double balance; + private String createDate; + private List<Transaction> transactions = new ArrayList<>(); + + public Account(String owner, String accountNumber) { + this.owner=owner; + this.accountNumber=accountNumber; + this.createDate=DateUtil.getSysdateAsStr(); + } + + public String getAccountNumber() { + return accountNumber; + } + + public void setAccountNumber(String accountNumber) { + this.accountNumber = accountNumber; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public double getBalance() { + return balance; + } + + public void setBalance(double balance) { + this.balance = balance; + } + + public String getCreateDate() { + return createDate; + } + + public void setCreateDate(String createDate) { + this.createDate = createDate; + } + + public void deposit(double amount) { + setBalance(getBalance()+amount); + } + + public void withdraw(double amount) throws InsufficientBalanceException { + if(amount>getBalance()) + throw new InsufficientBalanceException("Your balance is not enough"); + setBalance(getBalance()-amount); + + } + + public List<Transaction> getTransactions() { + return transactions; + } + + public void setTransactions(List<Transaction> transactions) { + this.transactions = transactions; + } + + public void post(Transaction trx) throws InsufficientBalanceException { + trx.update(this); + this.getTransactions().add(trx); + } + + + public void post(DepositTransaction depositTrx) { + this.deposit(depositTrx.getAmount()); + this.getTransactions().add(depositTrx); + } + + public void post(WithdrawalTransaction withdrawalTrx) throws InsufficientBalanceException { + this.withdraw(withdrawalTrx.getAmount()); + this.getTransactions().add(withdrawalTrx); + + } +} diff --git a/setup/banking/src/main/java/com/eteration/banking/model/DepositTransaction.java b/setup/banking/src/main/java/com/eteration/banking/model/DepositTransaction.java new file mode 100644 index 0000000..03c5862 --- /dev/null +++ b/setup/banking/src/main/java/com/eteration/banking/model/DepositTransaction.java @@ -0,0 +1,11 @@ +package com.eteration.banking.model; + +public class DepositTransaction extends Transaction { + public DepositTransaction(double amount) { + super(amount); + } + + public void update(Account account) { + account.deposit(this.getAmount()); + } +} diff --git a/setup/banking/src/main/java/com/eteration/banking/model/Transaction.java b/setup/banking/src/main/java/com/eteration/banking/model/Transaction.java new file mode 100644 index 0000000..aa99331 --- /dev/null +++ b/setup/banking/src/main/java/com/eteration/banking/model/Transaction.java @@ -0,0 +1,34 @@ +package com.eteration.banking.model; + +import java.util.Date; + +import com.eteration.banking.exception.InsufficientBalanceException; + + +public abstract class Transaction { + private Date date; + private double amount; + + public abstract void update(Account account) throws InsufficientBalanceException; + + public Transaction(double amount) { + this.date=new Date(); + this.setAmount(amount); + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public double getAmount() { + return amount; + } + + public void setAmount(double amount) { + this.amount = amount; + } +} diff --git a/setup/banking/src/main/java/com/eteration/banking/model/WithdrawalTransaction.java b/setup/banking/src/main/java/com/eteration/banking/model/WithdrawalTransaction.java new file mode 100644 index 0000000..9abdc6f --- /dev/null +++ b/setup/banking/src/main/java/com/eteration/banking/model/WithdrawalTransaction.java @@ -0,0 +1,12 @@ +package com.eteration.banking.model; + +import com.eteration.banking.exception.InsufficientBalanceException; + +public class WithdrawalTransaction extends Transaction { + public WithdrawalTransaction(double amount) { + super(amount); + } + public void update(Account account) throws InsufficientBalanceException { + account.withdraw(this.getAmount()); + } +} diff --git a/setup/banking/src/main/java/com/eteration/banking/util/DateUtil.java b/setup/banking/src/main/java/com/eteration/banking/util/DateUtil.java new file mode 100644 index 0000000..57535a3 --- /dev/null +++ b/setup/banking/src/main/java/com/eteration/banking/util/DateUtil.java @@ -0,0 +1,12 @@ +package com.eteration.banking.util; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class DateUtil { + + public static String getSysdateAsStr() { + SimpleDateFormat df=new SimpleDateFormat("dd.MM.yyyy"); + return df.format(new Date()); + } +} diff --git a/setup/banking/src/main/webapp/WEB-INF/web.xml b/setup/banking/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..52cf379 --- /dev/null +++ b/setup/banking/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> + <display-name>banking</display-name> + <welcome-file-list> + <welcome-file>index.html</welcome-file> + <welcome-file>index.htm</welcome-file> + <welcome-file>index.jsp</welcome-file> + <welcome-file>default.html</welcome-file> + <welcome-file>default.htm</welcome-file> + <welcome-file>default.jsp</welcome-file> + </welcome-file-list> +</web-app> \ No newline at end of file diff --git a/setup/banking/src/test/java/com/eteration/banking/tests/TestBankAccount.java b/setup/banking/src/test/java/com/eteration/banking/tests/TestBankAccount.java new file mode 100644 index 0000000..416717c --- /dev/null +++ b/setup/banking/src/test/java/com/eteration/banking/tests/TestBankAccount.java @@ -0,0 +1,77 @@ +package com.eteration.banking.tests; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.eteration.banking.exception.InsufficientBalanceException; +import com.eteration.banking.model.Account; +import com.eteration.banking.model.DepositTransaction; +import com.eteration.banking.model.WithdrawalTransaction; +import com.eteration.banking.util.DateUtil; + +public class TestBankAccount { + + @Test + public void testCreateAccountAndSetBalance0() { + Account account = new Account("Kerem Karaca", "17892"); + assertTrue(account.getOwner().equals("Kerem Karaca")); + assertTrue(account.getAccountNumber().equals("17892")); + assertTrue(account.getBalance() == 0); + } + + @Test + public void testSettingCreateDateWhenAccountCreated() { + Account account = new Account("Demet Demircan", "9834"); + String sysdateAsStr = DateUtil.getSysdateAsStr(); + assertTrue(account.getCreateDate().equals(sysdateAsStr)); + } + + @Test + public void testDepositIntoBankAccount() { + Account account = new Account("Demet Demircan", "9834"); + account.deposit(100); + assertTrue(account.getBalance() == 100); + } + + @Test + public void testWithdrawFromBankAccount() throws InsufficientBalanceException { + Account account = new Account("Demet Demircan", "9834"); + account.deposit(100); + assertTrue(account.getBalance() == 100); + account.withdraw(50); + assertTrue(account.getBalance() == 50); + } + + @Test + public void testWithdrawException() throws InsufficientBalanceException { + Assertions.assertThrows(InsufficientBalanceException.class, () -> { + Account account = new Account("Demet Demircan", "9834"); + account.deposit(100); + account.withdraw(500); + }); + } + + @Test + public void testTransactions() throws InsufficientBalanceException { + // Create account + Account account = new Account("Canan Kaya", "1234"); + assertTrue(account.getTransactions().size() == 0); + + // Deposit Transaction + DepositTransaction depositTrx = new DepositTransaction(100); + assertTrue(depositTrx.getDate() != null); + account.post(depositTrx); + assertTrue(account.getBalance() == 100); + assertTrue(account.getTransactions().size() == 1); + + // Withdrawal Transaction + WithdrawalTransaction withdrawalTrx = new WithdrawalTransaction(60); + assertTrue(withdrawalTrx.getDate() != null); + account.post(withdrawalTrx); + assertTrue(account.getBalance() == 40); + assertTrue(account.getTransactions().size() == 2); + } + +} diff --git a/solution/banking/_classpath.xml b/solution/banking/_classpath.xml new file mode 100644 index 0000000..9fc63d3 --- /dev/null +++ b/solution/banking/_classpath.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" output="target/classes" path="src/main/java"> + <attributes> + <attribute name="optional" value="true"/> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="src" output="target/test-classes" path="src/test/java"> + <attributes> + <attribute name="optional" value="true"/> + <attribute name="maven.pomderived" value="true"/> + <attribute name="test" value="true"/> + </attributes> + </classpathentry> + <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + <attribute name="test" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + <attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/> + </attributes> + </classpathentry> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"> + <attributes> + <attribute name="maven.pomderived" value="true"/> + </attributes> + </classpathentry> + <classpathentry kind="output" path="target/classes"/> +</classpath> diff --git a/solution/banking/_project.xml b/solution/banking/_project.xml new file mode 100644 index 0000000..4ba4a3e --- /dev/null +++ b/solution/banking/_project.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>banking</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.wst.common.project.facet.core.builder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.wst.validation.validationbuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.m2e.core.maven2Builder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jem.workbench.JavaEMFNature</nature> + <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + <nature>org.eclipse.m2e.core.maven2Nature</nature> + <nature>org.eclipse.wst.common.project.facet.core.nature</nature> + <nature>org.eclipse.wst.jsdt.core.jsNature</nature> + </natures> +</projectDescription> diff --git a/solution/banking/pom.xml b/solution/banking/pom.xml new file mode 100644 index 0000000..6bce626 --- /dev/null +++ b/solution/banking/pom.xml @@ -0,0 +1,43 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>banking.app</groupId> + <artifactId>banking</artifactId> + <version>0.0.1-SNAPSHOT</version> + <packaging>war</packaging> + <dependencies> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-api</artifactId> + <version>5.5.0</version> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + <version>5.5.0</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>2.10.0</version> + <scope>test</scope> + </dependency> + + + </dependencies> + <build> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <groupId>org.apache.maven.plugins</groupId> + <configuration> + <source>1.8</source> + <target>1.8</target> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/solution/banking/src/main/java/com/eteration/banking/dao/CurrencyDAO.java b/solution/banking/src/main/java/com/eteration/banking/dao/CurrencyDAO.java new file mode 100644 index 0000000..436e238 --- /dev/null +++ b/solution/banking/src/main/java/com/eteration/banking/dao/CurrencyDAO.java @@ -0,0 +1,5 @@ +package com.eteration.banking.dao; + +public interface CurrencyDAO { + public double getTLRate(String currencyCode); +} diff --git a/solution/banking/src/main/java/com/eteration/banking/exception/InsufficientBalanceException.java b/solution/banking/src/main/java/com/eteration/banking/exception/InsufficientBalanceException.java new file mode 100644 index 0000000..38542cc --- /dev/null +++ b/solution/banking/src/main/java/com/eteration/banking/exception/InsufficientBalanceException.java @@ -0,0 +1,12 @@ +package com.eteration.banking.exception; + +public class InsufficientBalanceException extends Exception{ + public InsufficientBalanceException() { + super(); + } + + public InsufficientBalanceException(String message) { + super(message); + } + +} diff --git a/solution/banking/src/main/java/com/eteration/banking/model/Account.java b/solution/banking/src/main/java/com/eteration/banking/model/Account.java new file mode 100644 index 0000000..0ce69c7 --- /dev/null +++ b/solution/banking/src/main/java/com/eteration/banking/model/Account.java @@ -0,0 +1,104 @@ +package com.eteration.banking.model; + +import java.util.ArrayList; +import java.util.List; + +import com.eteration.banking.dao.CurrencyDAO; +import com.eteration.banking.exception.InsufficientBalanceException; +import com.eteration.banking.util.DateUtil; + +public class Account { + private String accountNumber; + private String owner; + private double balance; + private String createDate; + private List<Transaction> transactions = new ArrayList<>(); + + private CurrencyDAO currencyDAO; + + public Account(String owner, String accountNumber) { + this.owner = owner; + this.accountNumber = accountNumber; + this.createDate = DateUtil.getSysdateAsStr(); + } + + public double convertBalance(String currencyCode) { + double rate = getCurrencyDAO().getTLRate(currencyCode); + return (int) (getBalance() / rate * 100) / 100.0; + } + + public CurrencyDAO getCurrencyDAO() { + return currencyDAO; + } + + public void setCurrencyDAO(CurrencyDAO currencyDAO) { + this.currencyDAO = currencyDAO; + } + + public String getAccountNumber() { + return accountNumber; + } + + public void setAccountNumber(String accountNumber) { + this.accountNumber = accountNumber; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public double getBalance() { + return balance; + } + + public void setBalance(double balance) { + this.balance = balance; + } + + public String getCreateDate() { + return createDate; + } + + public void setCreateDate(String createDate) { + this.createDate = createDate; + } + + public void deposit(double amount) { + setBalance(getBalance() + amount); + } + + public void withdraw(double amount) throws InsufficientBalanceException { + if (amount > getBalance()) + throw new InsufficientBalanceException("Your balance is not enough"); + setBalance(getBalance() - amount); + + } + + public List<Transaction> getTransactions() { + return transactions; + } + + public void setTransactions(List<Transaction> transactions) { + this.transactions = transactions; + } + + public void post(Transaction trx) throws InsufficientBalanceException { + trx.update(this); + this.getTransactions().add(trx); + } + + public void post(DepositTransaction depositTrx) { + this.deposit(depositTrx.getAmount()); + this.getTransactions().add(depositTrx); + } + + public void post(WithdrawalTransaction withdrawalTrx) throws InsufficientBalanceException { + this.withdraw(withdrawalTrx.getAmount()); + this.getTransactions().add(withdrawalTrx); + + } +} diff --git a/solution/banking/src/main/java/com/eteration/banking/model/DepositTransaction.java b/solution/banking/src/main/java/com/eteration/banking/model/DepositTransaction.java new file mode 100644 index 0000000..03c5862 --- /dev/null +++ b/solution/banking/src/main/java/com/eteration/banking/model/DepositTransaction.java @@ -0,0 +1,11 @@ +package com.eteration.banking.model; + +public class DepositTransaction extends Transaction { + public DepositTransaction(double amount) { + super(amount); + } + + public void update(Account account) { + account.deposit(this.getAmount()); + } +} diff --git a/solution/banking/src/main/java/com/eteration/banking/model/Transaction.java b/solution/banking/src/main/java/com/eteration/banking/model/Transaction.java new file mode 100644 index 0000000..aa99331 --- /dev/null +++ b/solution/banking/src/main/java/com/eteration/banking/model/Transaction.java @@ -0,0 +1,34 @@ +package com.eteration.banking.model; + +import java.util.Date; + +import com.eteration.banking.exception.InsufficientBalanceException; + + +public abstract class Transaction { + private Date date; + private double amount; + + public abstract void update(Account account) throws InsufficientBalanceException; + + public Transaction(double amount) { + this.date=new Date(); + this.setAmount(amount); + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public double getAmount() { + return amount; + } + + public void setAmount(double amount) { + this.amount = amount; + } +} diff --git a/solution/banking/src/main/java/com/eteration/banking/model/WithdrawalTransaction.java b/solution/banking/src/main/java/com/eteration/banking/model/WithdrawalTransaction.java new file mode 100644 index 0000000..9abdc6f --- /dev/null +++ b/solution/banking/src/main/java/com/eteration/banking/model/WithdrawalTransaction.java @@ -0,0 +1,12 @@ +package com.eteration.banking.model; + +import com.eteration.banking.exception.InsufficientBalanceException; + +public class WithdrawalTransaction extends Transaction { + public WithdrawalTransaction(double amount) { + super(amount); + } + public void update(Account account) throws InsufficientBalanceException { + account.withdraw(this.getAmount()); + } +} diff --git a/solution/banking/src/main/java/com/eteration/banking/util/DateUtil.java b/solution/banking/src/main/java/com/eteration/banking/util/DateUtil.java new file mode 100644 index 0000000..57535a3 --- /dev/null +++ b/solution/banking/src/main/java/com/eteration/banking/util/DateUtil.java @@ -0,0 +1,12 @@ +package com.eteration.banking.util; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class DateUtil { + + public static String getSysdateAsStr() { + SimpleDateFormat df=new SimpleDateFormat("dd.MM.yyyy"); + return df.format(new Date()); + } +} diff --git a/solution/banking/src/main/webapp/WEB-INF/web.xml b/solution/banking/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..52cf379 --- /dev/null +++ b/solution/banking/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> + <display-name>banking</display-name> + <welcome-file-list> + <welcome-file>index.html</welcome-file> + <welcome-file>index.htm</welcome-file> + <welcome-file>index.jsp</welcome-file> + <welcome-file>default.html</welcome-file> + <welcome-file>default.htm</welcome-file> + <welcome-file>default.jsp</welcome-file> + </welcome-file-list> +</web-app> \ No newline at end of file diff --git a/solution/banking/src/test/java/com/eteration/banking/tests/TestBankAccount.java b/solution/banking/src/test/java/com/eteration/banking/tests/TestBankAccount.java new file mode 100644 index 0000000..7f95f57 --- /dev/null +++ b/solution/banking/src/test/java/com/eteration/banking/tests/TestBankAccount.java @@ -0,0 +1,97 @@ +package com.eteration.banking.tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import com.eteration.banking.dao.CurrencyDAO; +import com.eteration.banking.exception.InsufficientBalanceException; +import com.eteration.banking.model.Account; +import com.eteration.banking.model.DepositTransaction; +import com.eteration.banking.model.WithdrawalTransaction; +import com.eteration.banking.util.DateUtil; + +import static org.mockito.Mockito.*; + +public class TestBankAccount { + + @Test + public void testCurrencyConverter() { + Account account = new Account("Canan","1234"); + CurrencyDAO mockedCurrencyDAO = mock(CurrencyDAO.class); + account.post(new DepositTransaction(1000)); + when(mockedCurrencyDAO.getTLRate("USD")).thenReturn(5.34); + when(mockedCurrencyDAO.getTLRate("EUR")).thenReturn(6.06); + account.setCurrencyDAO(mockedCurrencyDAO); + + assertEquals(187.26,account.convertBalance("USD"),0);; + assertEquals(165.01,account.convertBalance("EUR"),0); + verify(mockedCurrencyDAO).getTLRate("EUR"); + verify(mockedCurrencyDAO).getTLRate("USD"); + } + + + @Test + public void testCreateAccountAndSetBalance0() { + Account account = new Account("Kerem Karaca", "17892"); + assertTrue(account.getOwner().equals("Kerem Karaca")); + assertTrue(account.getAccountNumber().equals("17892")); + assertTrue(account.getBalance() == 0); + } + + @Test + public void testSettingCreateDateWhenAccountCreated() { + Account account = new Account("Demet Demircan", "9834"); + String sysdateAsStr = DateUtil.getSysdateAsStr(); + assertTrue(account.getCreateDate().equals(sysdateAsStr)); + } + + @Test + public void testDepositIntoBankAccount() { + Account account = new Account("Demet Demircan", "9834"); + account.deposit(100); + assertTrue(account.getBalance() == 100); + } + + @Test + public void testWithdrawFromBankAccount() throws InsufficientBalanceException { + Account account = new Account("Demet Demircan", "9834"); + account.deposit(100); + assertTrue(account.getBalance() == 100); + account.withdraw(50); + assertTrue(account.getBalance() == 50); + } + + @Test + public void testWithdrawException() throws InsufficientBalanceException { + Assertions.assertThrows(InsufficientBalanceException.class, () -> { + Account account = new Account("Demet Demircan", "9834"); + account.deposit(100); + account.withdraw(500); + }); + } + + @Test + public void testTransactions() throws InsufficientBalanceException { + // Create account + Account account = new Account("Canan Kaya", "1234"); + assertTrue(account.getTransactions().size() == 0); + + // Deposit Transaction + DepositTransaction depositTrx = new DepositTransaction(100); + assertTrue(depositTrx.getDate() != null); + account.post(depositTrx); + assertTrue(account.getBalance() == 100); + assertTrue(account.getTransactions().size() == 1); + + // Withdrawal Transaction + WithdrawalTransaction withdrawalTrx = new WithdrawalTransaction(60); + assertTrue(withdrawalTrx.getDate() != null); + account.post(withdrawalTrx); + assertTrue(account.getBalance() == 40); + assertTrue(account.getTransactions().size() == 2); + } + +} -- GitLab