There is a discount on the Gatsby hair cream
– buy 1 item get 50% discount on next item.
– there is no offer on ‘Bvlgiri soap’.
Let’s implement our IOffer for the discount offer class- DiscountOnNextItemOffer
package com.tdd.shoppingcart;
public class DiscountOnNextItemOffer implements IOffer {
private double discountPercentage;
public DiscountOnNextItemOffer(double discountPercentage) {
this.discountPercentage = discountPercentage;
}
@Override
public void applyOffer(Product product) {
}
// get/set
}
Requirement: Apply discount on shopping cart
When: Add 2 unit of ‘Gatsby hair cream’, unit price 30 Rupees.
Then:
– The product count of cart should be 1.
– The total price of product should be 45.
– The total value of cart should be 45.0 rupees.
Add a test for above requirement to the test class.
@Test
public void testApplyBuyOneGetFiftyPercentDiscountOnNextOfferToTheCart(){
IOffer offer = new DiscountOnNextItemOffer(50.0);
ShoppingCart cart = new ShoppingCart();
cart.setOffer(offer);
Product gatsByCream = new Product("Gatsby hair cream", 2, 60.0);
cart.addProduct(gatsByCream );
Assert.assertEquals(1, cart.getProductCount());
Assert.assertEquals(45.0, cart.getProductByName("Gatsby hair cream").getTotalPrice(),0.0);
Assert.assertEquals(45.0, cart.getTotalCartValue(),0.0);
}
The test will have compilation error since we don’t have getProductByname() method in ShoppingCart. Let’s add the method to the ShoppingCart.
public Product getProductByName(String name) {
if (productList.size() > 0) {
for (Product product : productList) {
if (product.getProductName().equals(name)) {
return product;
}
}
}
return null;
}
Now If you run the test, it will fail since we have not added any logic for % discount. Refactor the DiscountOnNextItemOffer class.
package com.tdd.shoppingcart;
public class DiscountOnNextItemOffer implements IOffer {
private double discountPercentage;
public DiscountOnNextItemOffer(double discountPercentage) {
this.discountPercentage = discountPercentage;
}
@Override
public void applyOffer(Product product) {
int totalQuantity = product.getQuantity();
double unitPrice = product.getTotalPrice() / product.getQuantity();
while (totalQuantity > 1) {
double price = product.getTotalPrice();
product.setTotalPrice(price - (unitPrice / (100/discountPercentage)));
totalQuantity = totalQuantity - 2;
}
}
// get/set
}
Now run the test. It will pass without any problem.

Requirement: Apply discount on shopping cart
When: Add 5 unit of ‘Gatsby hair cream’, unit price 30 Rupees.
Then:
– The product count of cart should be 1.
– The total price of product should be 120.
– The total value of cart should be 120.0 rupees.
Add test for the above requirements.
@Test
public void testApplyBuyOneGetFiftyPercentDiscountOnNextOfferToTheMultipleProductsInCart(){
IOffer offer = new DiscountOnNextItemOffer(50.0);
ShoppingCart cart = new ShoppingCart();
cart.setOffer(offer);
Product gatsByCream = new Product("Gatsby hair cream", 5, 150.0);
cart.addProduct(gatsByCream);
Assert.assertEquals(1, cart.getProductCount());
Assert.assertEquals(120.0, cart.getProductByName("Gatsby hair cream").getTotalPrice(),0.0);
Assert.assertEquals(120.0, cart.getTotalCartValue(),0.0);
}
The test will pass without any refactoring.
This is all. Here my aim was to give you a feel of TDD. The presented design may not be optimum and further refactoring may be required. You can keep adding your requirements and follow the cycle- Write failing Test – Write code to make test pass – refactor for the best possible design.
To know more about TDD you can read following books:
Growing Object Oriented Software Guided By Tests
Test Driven Development By Example
Test Driven