├── .gitignore ├── README.md ├── pom.xml └── src ├── main └── java │ └── com │ └── danix │ └── code │ └── smell │ └── example001 │ ├── Account.java │ ├── AccountType.java │ ├── Company.java │ ├── Customer.java │ ├── CustomerFactory.java │ ├── CustomerReport.java │ ├── Money.java │ ├── Person.java │ └── README.md └── test └── java └── com └── danix └── code └── smell └── example001 ├── AccountTest.java ├── AccountTestUtils.java ├── CompanyTest.java ├── CustomerReportTest.java ├── CustomerTest.java ├── CustomerTestUtils.java ├── MoneyTest.java └── PersonTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml 3 | .classpath 4 | .project 5 | .settings/ 6 | target/ 7 | nbproject/ 8 | nb-configuration.xml 9 | bin/ 10 | local.properties 11 | project.properties 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | code-smell 2 | ========== 3 | 4 | Code example for the [Refactoring Presentation](https://docs.google.com/presentation/d/1VjbJONDU3P9VAdB_HhhT1oBB4uOub80T_41yDmndwTw/edit?usp=sharing) 5 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | code-smell 7 | code-smell 8 | 0.0.1-SNAPSHOT 9 | 10 | 11 | com.google.guava 12 | guava 13 | 14.0.1 14 | jar 15 | 16 | 17 | com.google.code.findbugs 18 | jsr305 19 | 2.0.1 20 | jar 21 | 22 | 23 | 24 | junit 25 | junit 26 | 4.11 27 | test 28 | jar 29 | 30 | 31 | org.hamcrest 32 | hamcrest-all 33 | 1.3 34 | test 35 | jar 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/main/java/com/danix/code/smell/example001/Account.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | /** 4 | * @author danix 5 | */ 6 | public class Account { 7 | 8 | private String iban; 9 | 10 | private AccountType type; 11 | 12 | private int daysOverdrawn; 13 | 14 | private Money money; 15 | 16 | private Customer customer; 17 | 18 | public Account(final AccountType type, final int daysOverdrawn) { 19 | super(); 20 | this.type = type; 21 | this.daysOverdrawn = daysOverdrawn; 22 | } 23 | 24 | public double bankcharge() { 25 | double result = 4.5; 26 | 27 | result += overdraftCharge(); 28 | 29 | return result; 30 | } 31 | 32 | private double overdraftCharge() { 33 | if (type.isPremium()) { 34 | double result = 10; 35 | if (getDaysOverdrawn() > 7) { 36 | result += (getDaysOverdrawn() - 7) * 1.0; 37 | } 38 | 39 | return result; 40 | } else { 41 | return getDaysOverdrawn() * 1.75; 42 | } 43 | } 44 | 45 | public double overdraftFee() { 46 | if (type.isPremium()) { 47 | return 0.10; 48 | } else { 49 | return 0.20; 50 | } 51 | } 52 | 53 | public int getDaysOverdrawn() { 54 | return daysOverdrawn; 55 | } 56 | 57 | public String getIban() { 58 | return iban; 59 | } 60 | 61 | public void setIban(final String iban) { 62 | this.iban = iban; 63 | } 64 | 65 | public void setMoney(final Money money) { 66 | this.money = money; 67 | } 68 | 69 | public Customer getCustomer() { 70 | return customer; 71 | } 72 | 73 | public void setCustomer(final Customer customer) { 74 | this.customer = customer; 75 | } 76 | 77 | public AccountType getType() { 78 | return type; 79 | } 80 | 81 | public boolean isOverdraft() { 82 | return money.getAmount() < 0; 83 | } 84 | 85 | public void substract(final Money money) { 86 | this.money = this.money.substract(money); 87 | } 88 | 89 | public double getMoneyAmount() { 90 | return money.getAmount(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/danix/code/smell/example001/AccountType.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | /** 4 | * @author danix 5 | */ 6 | public class AccountType { 7 | private boolean premium; 8 | 9 | AccountType(boolean premium) { 10 | this.premium = premium; 11 | } 12 | 13 | public boolean isPremium() { 14 | return premium; 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | return premium ? "premium" : "normal"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/danix/code/smell/example001/Company.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | /** 4 | * @author danix 5 | */ 6 | public class Company extends Customer { 7 | 8 | protected double companyOverdraftDiscount = 1; 9 | 10 | Company(final String name, final String email, final Account account, final double companyOverdraftDiscount) { 11 | super(name, email, account); 12 | this.companyOverdraftDiscount = companyOverdraftDiscount; 13 | } 14 | 15 | @Override 16 | public void withdraw(final Money money) { 17 | if (account.getType().isPremium()) { 18 | if (account.isOverdraft()) { 19 | 20 | // 50 percent discount for overdraft for premium account 21 | account.substract(Money.newInstance( 22 | money.getAmount() + money.getAmount() * account.overdraftFee() * companyOverdraftDiscount / 2, 23 | money.getCurrency())); 24 | } else { 25 | account.substract(Money.newInstance(money.getAmount(), money.getCurrency())); 26 | } 27 | } else { 28 | if (account.isOverdraft()) { 29 | 30 | // no discount for overdraft for not premium account 31 | account.substract(Money.newInstance( 32 | money.getAmount() + money.getAmount() * account.overdraftFee() * companyOverdraftDiscount, 33 | money.getCurrency())); 34 | } else { 35 | account.substract(Money.newInstance(money.getAmount(), money.getCurrency())); 36 | } 37 | } 38 | } 39 | 40 | @Override 41 | protected String getFullName() { 42 | return name; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/danix/code/smell/example001/Customer.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | /** 4 | * @author danix 5 | */ 6 | public abstract class Customer { 7 | 8 | protected String name; 9 | protected String email; 10 | protected Account account; 11 | 12 | Customer(final String name, final String email, final Account account) { 13 | this.name = name; 14 | this.email = email; 15 | this.account = account; 16 | } 17 | 18 | public abstract void withdraw(Money money); 19 | 20 | protected abstract String getFullName(); 21 | 22 | public String getName() { 23 | return name; 24 | } 25 | 26 | public void setName(final String name) { 27 | this.name = name; 28 | } 29 | 30 | public String getEmail() { 31 | return email; 32 | } 33 | 34 | public void setEmail(final String email) { 35 | this.email = email; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/danix/code/smell/example001/CustomerFactory.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | /** 4 | * @author danix 5 | */ 6 | public class CustomerFactory { 7 | 8 | public Customer createCompany(String name, String email, Account account, double companyOverdraftDiscount) { 9 | return new Company(name, email, account, companyOverdraftDiscount); 10 | } 11 | 12 | public Customer createPerson(String name, String surname, String email, Account account) { 13 | return new Person(name, surname, email, account); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/danix/code/smell/example001/CustomerReport.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | import static com.google.common.base.Preconditions.checkNotNull; 4 | 5 | import javax.annotation.Nonnull; 6 | 7 | /** 8 | * @author danix 9 | */ 10 | public class CustomerReport { 11 | 12 | private final Customer customer; 13 | private final Account account; 14 | 15 | public CustomerReport(@Nonnull final Customer customer, @Nonnull final Account account) { 16 | this.customer = checkNotNull(customer); 17 | this.account = checkNotNull(account); 18 | } 19 | 20 | public String printCustomerDaysOverdrawn() { 21 | String fullName = customer.getFullName(); 22 | 23 | String accountDescription = "Account: IBAN: " + account.getIban() + ", Days Overdrawn: " 24 | + account.getDaysOverdrawn(); 25 | return fullName + accountDescription; 26 | } 27 | 28 | public String printCustomerMoney() { 29 | String fullName = customer.getFullName(); 30 | String accountDescription = ""; 31 | accountDescription += "Account: IBAN: " + account.getIban() + ", Money: " + account.getMoneyAmount(); 32 | return fullName + accountDescription; 33 | } 34 | 35 | public String printCustomerAccount() { 36 | return "Account: IBAN: " + account.getIban() + ", Money: " + account.getMoneyAmount() + ", Account type: " 37 | + account.getType(); 38 | } 39 | 40 | public String printCustomer() { 41 | return customer.getName() + " " + customer.getEmail(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/danix/code/smell/example001/Money.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | import javax.annotation.Nonnull; 4 | 5 | import static com.google.common.base.Preconditions.checkNotNull; 6 | 7 | /** 8 | * @author danix 9 | */ 10 | public class Money { 11 | 12 | public static final String EUR_CURRENCY = "EUR"; 13 | private final double amount; 14 | private final String currency; 15 | 16 | private Money(double amount, @Nonnull String currency) { 17 | this.amount = amount; 18 | this.currency = checkNotNull(currency); 19 | } 20 | 21 | public static Money newInstance(double amount, @Nonnull String currency) { 22 | return new Money(amount, currency); 23 | } 24 | 25 | public static Money newEuro(double amount) { 26 | return new Money(amount, EUR_CURRENCY); 27 | } 28 | 29 | public double getAmount() { 30 | return amount; 31 | } 32 | 33 | @Nonnull 34 | public String getCurrency() { 35 | return currency; 36 | } 37 | 38 | @Nonnull 39 | public Money substract(@Nonnull Money money) { 40 | checkNotNull(money); 41 | if (!money.getCurrency().equals(currency)) { 42 | throw new RuntimeException("Can't substract different currencies!"); 43 | } 44 | return new Money(this.amount - money.amount, currency); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/danix/code/smell/example001/Person.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | /** 4 | * @author danix 5 | */ 6 | public class Person extends Customer { 7 | protected String surname; 8 | 9 | Person(final String name, final String surname, final String email, final Account account) { 10 | super(name, email, account); 11 | this.surname = surname; 12 | } 13 | 14 | @Override 15 | public void withdraw(final Money money) { 16 | if (account.getType().isPremium()) { 17 | if (account.isOverdraft()) { 18 | account.substract(Money.newInstance(money.getAmount() + money.getAmount() * account.overdraftFee(), 19 | money.getCurrency())); 20 | } else { 21 | account.substract(Money.newInstance(money.getAmount(), money.getCurrency())); 22 | } 23 | } else { 24 | if (account.isOverdraft()) { 25 | account.substract(Money.newInstance(money.getAmount() + money.getAmount() * account.overdraftFee(), 26 | money.getCurrency())); 27 | } else { 28 | account.substract(Money.newInstance(money.getAmount(), money.getCurrency())); 29 | } 30 | } 31 | } 32 | 33 | @Override 34 | protected String getFullName() { 35 | return name + " " + surname + " "; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/danix/code/smell/example001/README.md: -------------------------------------------------------------------------------- 1 | # Code smells 2 | 3 | - Duplicated Code 4 | - For determining the fullName of the Customer 5 | - In the customer.withdraw method we can see similar code 6 | - Possible refactoring: Extract method 7 | 8 | - Long Method 9 | - Customer.withdraw method has more than 5 lines of code 10 | - Possible refactorings: Extract method 11 | 12 | - Divergent Change 13 | - Customer class has more than one reason to change. This is a violation of the SRP (Single Responsibility Principle) 14 | - Possible refactorings: Extract class 15 | 16 | - Comments 17 | - The comments in the customer.withdraw method 18 | - Possible refactorings: make code speak for itself 19 | 20 | - Switch Statements 21 | - Customer.withdraw method has a some switches 22 | - Does not respect OCP (Open Closed Principle) 23 | - Every time we want to add a new customer type we have to modify the two switches 24 | - Possible Refactorings: Replace conditional with polymorphism 25 | 26 | - Feature Envy 27 | - Customer class has a fascination over the methods of the Account class 28 | - see the Customer.printCustomerAccount 29 | - also Customer.withdraw 30 | - high coupled with the Account class 31 | - Possible refactorings: Move method 32 | 33 | - Inappropriate Intimacy 34 | - Customer.printCustomerDaysOverdrawn only uses methods from the Account class 35 | - Account.printCustomer only uses methods from the Customer class 36 | - it's a bidirectional feature envy 37 | - Possible refactorings: Move methods 38 | 39 | - Primitive Obsession 40 | - Use a primitive type instead of a small object 41 | - Account.money should be in it's own class 42 | - Possible refactorings: Extract class, Introduce Parameter object 43 | 44 | - Data Clumps 45 | - This is about groups of objects that are always grouped together 46 | - Account.money and Account.currency should have a class 47 | - Possible refactorings: Extract class, Introduce Parameter object 48 | 49 | - Lazy Class 50 | - A class that's not doing enough 51 | - AccountType 52 | - Possible refactorings: Inline class -------------------------------------------------------------------------------- /src/test/java/com/danix/code/smell/example001/AccountTest.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | import static org.hamcrest.CoreMatchers.is; 4 | 5 | import static org.junit.Assert.assertThat; 6 | 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | /** 11 | * @author danix 12 | */ 13 | public class AccountTest { 14 | 15 | private CustomerFactory customerFactory; 16 | 17 | @Before 18 | public void setUp() { 19 | customerFactory = new CustomerFactory(); 20 | } 21 | 22 | @Test 23 | public void testBankchargePremiumLessThanAWeek() { 24 | Account account = getPremiumAccount(5); 25 | assertThat(account.bankcharge(), is(14.5)); 26 | } 27 | 28 | @Test 29 | public void testBankchargePremiumMoreThanAWeek() { 30 | Account account = getPremiumAccount(9); 31 | assertThat(account.bankcharge(), is(16.5)); 32 | } 33 | 34 | @Test 35 | public void testOverdraftFeePremium() { 36 | Account account = getPremiumAccount(9); 37 | assertThat(account.overdraftFee(), is(0.10)); 38 | } 39 | 40 | @Test 41 | public void testOverdraftFeeNotPremium() { 42 | Account account = getNormalAccount(); 43 | assertThat(account.overdraftFee(), is(0.20)); 44 | } 45 | 46 | private Account getNormalAccount() { 47 | AccountType premium = new AccountType(false); 48 | return new Account(premium, 9); 49 | } 50 | 51 | private Account getPremiumAccount(final int daysOverdrawn) { 52 | AccountType normal = new AccountType(true); 53 | return new Account(normal, daysOverdrawn); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/com/danix/code/smell/example001/AccountTestUtils.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | /** 4 | * @author danix 5 | */ 6 | public class AccountTestUtils { 7 | 8 | static Account getAccountByTypeAndMoney(boolean premium, double money) { 9 | AccountType accountType = new AccountType(premium); 10 | Account account = new Account(accountType, 9); 11 | account.setIban("RO023INGB434321431241"); 12 | account.setMoney(Money.newEuro(money)); 13 | return account; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/com/danix/code/smell/example001/CompanyTest.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | import static org.hamcrest.CoreMatchers.is; 4 | 5 | import static org.junit.Assert.assertThat; 6 | 7 | import static com.danix.code.smell.example001.AccountTestUtils.getAccountByTypeAndMoney; 8 | import static com.danix.code.smell.example001.CustomerTestUtils.getCompanyCustomer; 9 | 10 | import org.junit.Test; 11 | 12 | /** 13 | * @author danix 14 | */ 15 | public class CompanyTest { 16 | 17 | private static final Money SOME_EURO = Money.newEuro(10); 18 | 19 | @Test 20 | public void testWithdrawCompanyWithNormalAccount() throws Exception { 21 | Account account = getAccountByTypeAndMoney(false, 34); 22 | Customer customer = getCompanyCustomer(account); 23 | customer.withdraw(SOME_EURO); 24 | assertThat(account.getMoneyAmount(), is(24.0)); 25 | } 26 | 27 | @Test 28 | public void testWithdrawCompanyWithNormalAccountAndOverdraft() throws Exception { 29 | Account account = getAccountByTypeAndMoney(false, -10); 30 | Customer customer = getCompanyCustomer(account); 31 | customer.withdraw(SOME_EURO); 32 | assertThat(account.getMoneyAmount(), is(-21.0)); 33 | } 34 | 35 | @Test 36 | public void testWithdrawCompanyWithPremiumAccount() throws Exception { 37 | Account account = getAccountByTypeAndMoney(true, 34); 38 | Customer customer = getCompanyCustomer(account); 39 | customer.withdraw(SOME_EURO); 40 | assertThat(account.getMoneyAmount(), is(24.0)); 41 | } 42 | 43 | @Test 44 | public void testWithdrawCompanyWithPremiumAccountAndOverdraft() throws Exception { 45 | Account account = getAccountByTypeAndMoney(true, -10); 46 | Customer customer = getCompanyCustomer(account); 47 | customer.withdraw(SOME_EURO); 48 | assertThat(account.getMoneyAmount(), is(-20.25)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/danix/code/smell/example001/CustomerReportTest.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | import static org.hamcrest.CoreMatchers.is; 4 | 5 | import static org.junit.Assert.assertThat; 6 | 7 | import static com.danix.code.smell.example001.CustomerTestUtils.getAccount; 8 | import static com.danix.code.smell.example001.CustomerTestUtils.getPersonCustomer; 9 | 10 | import org.junit.Test; 11 | 12 | /** 13 | * @author dpersa 14 | */ 15 | public class CustomerReportTest { 16 | 17 | @Test 18 | public void testPrintCustomerDaysOverdrawn() throws Exception { 19 | Account account = getAccount(false); 20 | Customer customer = getPersonCustomer(account); 21 | CustomerReport customerReport = new CustomerReport(customer, account); 22 | assertThat(customerReport.printCustomerDaysOverdrawn(), 23 | is("danix dan Account: IBAN: RO023INGB434321431241, Days Overdrawn: 9")); 24 | } 25 | 26 | @Test 27 | public void testPrintCustomerMoney() throws Exception { 28 | Account account = getAccount(false); 29 | Customer customer = getPersonCustomer(account); 30 | CustomerReport customerReport = new CustomerReport(customer, account); 31 | assertThat(customerReport.printCustomerMoney(), 32 | is("danix dan Account: IBAN: RO023INGB434321431241, Money: 34.0")); 33 | } 34 | 35 | @Test 36 | public void testPrintCustomerAccountNormal() throws Exception { 37 | Account account = getAccount(false); 38 | Customer customer = getPersonCustomer(account); 39 | CustomerReport customerReport = new CustomerReport(customer, account); 40 | assertThat(customerReport.printCustomerAccount(), 41 | is("Account: IBAN: RO023INGB434321431241, Money: 34.0, Account type: normal")); 42 | } 43 | 44 | @Test 45 | public void testPrintCustomerAccountPremium() throws Exception { 46 | Account account = getAccount(true); 47 | Customer customer = getPersonCustomer(account); 48 | CustomerReport customerReport = new CustomerReport(customer, account); 49 | assertThat(customerReport.printCustomerAccount(), 50 | is("Account: IBAN: RO023INGB434321431241, Money: 34.0, Account type: premium")); 51 | } 52 | 53 | @Test 54 | public void testPrintCustomer() { 55 | Account account = getAccount(false); 56 | Customer customer = getPersonCustomer(account); 57 | CustomerReport customerReport = new CustomerReport(customer, account); 58 | assertThat(customerReport.printCustomer(), is("danix dan@mail.com")); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/com/danix/code/smell/example001/CustomerTest.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | /** 4 | * @author danix 5 | */ 6 | public class CustomerTest { } 7 | -------------------------------------------------------------------------------- /src/test/java/com/danix/code/smell/example001/CustomerTestUtils.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | /** 4 | * @author danix 5 | */ 6 | public class CustomerTestUtils { 7 | 8 | private static CustomerFactory customerFactory = new CustomerFactory(); 9 | 10 | static Customer getCompanyCustomer(final Account account) { 11 | Customer customer = customerFactory.createCompany("company", "company@mail.com", account, 0.50); 12 | account.setCustomer(customer); 13 | return customer; 14 | } 15 | 16 | static Customer getPersonCustomer(final Account account) { 17 | Customer customer = customerFactory.createPerson("danix", "dan", "dan@mail.com", account); 18 | account.setCustomer(customer); 19 | return customer; 20 | } 21 | 22 | static Customer getPersonWithAccount(final boolean premium) { 23 | AccountType accountType = new AccountType(premium); 24 | Account account = new Account(accountType, 9); 25 | account.setIban("RO023INGB434321431241"); 26 | account.setMoney(Money.newEuro(34.0)); 27 | 28 | Customer customer = getPersonCustomer(account); 29 | return customer; 30 | } 31 | 32 | static Account getAccount(final boolean premium) { 33 | AccountType accountType = new AccountType(premium); 34 | Account account = new Account(accountType, 9); 35 | account.setIban("RO023INGB434321431241"); 36 | account.setMoney(Money.newEuro(34.0)); 37 | return account; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/danix/code/smell/example001/MoneyTest.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | import static org.hamcrest.CoreMatchers.is; 7 | 8 | /** 9 | * @author danix 10 | */ 11 | public class MoneyTest { 12 | 13 | 14 | @Test 15 | public void testSubstract() throws Exception { 16 | Money difference = Money.newEuro(20.0).substract(Money.newEuro(10.0)); 17 | Assert.assertThat(difference.getAmount(), is(10.0)); 18 | Assert.assertThat(difference.getCurrency(), is(Money.EUR_CURRENCY)); 19 | } 20 | 21 | @Test 22 | public void testSubstractNegative() throws Exception { 23 | Money difference = Money.newEuro(20.0).substract(Money.newEuro(100.0)); 24 | Assert.assertThat(difference.getAmount(), is(-80.0)); 25 | Assert.assertThat(difference.getCurrency(), is(Money.EUR_CURRENCY)); 26 | } 27 | 28 | @Test(expected = RuntimeException.class) 29 | public void testSubstractDifferentCurrencies() throws Exception { 30 | Money.newEuro(20.0).substract(Money.newInstance(10.0, "USD")); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/danix/code/smell/example001/PersonTest.java: -------------------------------------------------------------------------------- 1 | package com.danix.code.smell.example001; 2 | 3 | import static org.hamcrest.CoreMatchers.is; 4 | 5 | import static org.junit.Assert.assertThat; 6 | 7 | import static com.danix.code.smell.example001.AccountTestUtils.getAccountByTypeAndMoney; 8 | import static com.danix.code.smell.example001.CustomerTestUtils.getPersonCustomer; 9 | 10 | import org.junit.Test; 11 | 12 | /** 13 | * @author danix 14 | */ 15 | public class PersonTest { 16 | 17 | public static final Money SOME_EURO = Money.newEuro(10); 18 | 19 | @Test 20 | public void testWithdrawPersonWithNormalAccount() throws Exception { 21 | Account account = getAccountByTypeAndMoney(false, 34.0); 22 | Customer customer = getPersonCustomer(account); 23 | customer.withdraw(SOME_EURO); 24 | assertThat(account.getMoneyAmount(), is(24.0)); 25 | } 26 | 27 | @Test 28 | public void testWithdrawPersonWithNormalAccountAndOverdraft() throws Exception { 29 | Account account = getAccountByTypeAndMoney(false, -10.0); 30 | Customer customer = getPersonCustomer(account); 31 | customer.withdraw(SOME_EURO); 32 | assertThat(account.getMoneyAmount(), is(-22.0)); 33 | } 34 | 35 | @Test 36 | public void testWithdrawPersonWithPremiumAccount() throws Exception { 37 | Account account = getAccountByTypeAndMoney(true, 34.0); 38 | Customer customer = getPersonCustomer(account); 39 | customer.withdraw(SOME_EURO); 40 | assertThat(account.getMoneyAmount(), is(24.0)); 41 | } 42 | 43 | @Test 44 | public void testWithdrawPersonWithPremiumAccountAndOverdraft() throws Exception { 45 | Account account = getAccountByTypeAndMoney(true, -10.0); 46 | Customer customer = getPersonCustomer(account); 47 | customer.withdraw(SOME_EURO); 48 | assertThat(account.getMoneyAmount(), is(-21.0)); 49 | } 50 | } 51 | --------------------------------------------------------------------------------