Skip to content

Instantly share code, notes, and snippets.

@kevinrutherford
Created February 9, 2015 19:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevinrutherford/5adea38fc1012b9f2247 to your computer and use it in GitHub Desktop.
Save kevinrutherford/5adea38fc1012b9f2247 to your computer and use it in GitHub Desktop.
The checkout kata after 5 stages of connascence removal
public class Checkout {
private Money balance = Money.ZERO;
private MultibuyDiscount discount;
public Checkout(MultibuyDiscount discount) {
this.discount = discount.reset();
}
public Checkout scan(String sku, Money price) {
balance = balance.add(price);
balance = balance.subtract(discount.discountFor(sku));
return this;
}
public Money currentBalance() {
return balance;
}
}
import static org.junit.Assert.assertEquals;
import java.util.Random;
import org.junit.Test;
public class CheckoutTests {
@Test
public void basicPrices() {
Money priceOfA = randomPrice();
MultibuyDiscount discount = new MultibuyDiscount("A", Money.fromPence(20), 2);
Checkout checkout = new Checkout(discount);
Money priceOfB = randomPrice();
checkout.scan("A", priceOfA).scan("B", priceOfB);
assertEquals(priceOfA.add(priceOfB), checkout.currentBalance());
}
@Test
public void discountForTwoAs() {
Money priceOfA = randomPrice();
Money priceOfB = randomPrice();
MultibuyDiscount discount = new MultibuyDiscount("A", Money.fromPence(20), 2);
Checkout checkout = new Checkout(discount);
checkout.scan("A", priceOfA).scan("B", priceOfB)
.scan("A", priceOfA);
Money expectedTotal = priceOfA.add(priceOfA).add(priceOfB)
.subtract(Money.fromPence(20));
assertEquals(expectedTotal, checkout.currentBalance());
}
@Test
public void independentCheckouts() {
Money priceOfA = randomPrice();
MultibuyDiscount discount = new MultibuyDiscount("A", Money.fromPence(20), 2);
Checkout checkout1 = new Checkout(discount);
Checkout checkout2 = new Checkout(discount);
checkout1.scan("A", priceOfA);
checkout2.scan("A", priceOfA);
assertEquals(priceOfA, checkout1.currentBalance());
assertEquals(priceOfA, checkout2.currentBalance());
}
private Money randomPrice() {
int pence = new Random().nextInt(1000);
return Money.fromPence(pence);
}
}
public class Money {
public static final Money ZERO = new Money(0);
private int pence;
private Money(int pence) {
this.pence = pence;
}
public static Money fromPence(int pence) {
return new Money(pence);
}
public Money add(Money other) {
return new Money(pence + other.pence);
}
public Money subtract(Money other) {
return new Money(pence - other.pence);
}
@Override
public boolean equals(Object other) {
Money m = (Money) other;
return pence == m.pence;
}
@Override
public int hashCode() {
return new Integer(pence).hashCode();
}
@Override
public String toString() {
return "" + pence + "p";
}
}
public class MultibuyDiscount {
private String watchedSku;
private Money discount;
private int trigger;
private int itemsSeen = 0;
public MultibuyDiscount(String sku, Money discount, int trigger) {
this.watchedSku = sku;
this.discount = discount;
this.trigger = trigger;
}
public Money discountFor(String sku) {
if (sku.equals(watchedSku))
itemsSeen++;
return (itemsSeen == trigger) ? discount : Money.ZERO;
}
public MultibuyDiscount reset() {
return new MultibuyDiscount(watchedSku, discount, trigger);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment