title: How to design the classes for a simple shopping cart example using TDD approach?
body: <p>I came across a shopping cart exercise to learn OOAD and TDD using Java.</p>
  
  <p>The exercise is:</p>
  
  <hr>
  
  <p><strong>First Step</strong>: Design a checkout system</p>
  
  <ul>
  <li>Build  a checkout system for a shop which sells 3 products say Bread, Milk, and Bananas.</li>
  <li>Costs of the products are : Bread - $1, Milk - $0.60 and Banana - $0.40</li>
  <li>Build a system to checkout a shopping cart that can have multiples of these 3 products and displays the order total. 
  Examples are:
  Bread, Milk, Banana  = $2.00
  Bread, Bread, Milk, Banana  = $3.00
  Milk, Banana, Milk, Banana  = $2.00</li>
  </ul>
  
  <p><strong>As a next step</strong>: enhance the code to apply the below discounts and offers</p>
  
  <p>Buy one bread and get another bread for free
   Buy 3 Milk for the price of 2
   Buy 2 Bananas and get one free</p>
  
  <p>First build a simplest solution to satisfy the first case alone. Then re-factor the code to extend it for 2nd step.</p>
  
  <hr>
  
  <p>The first step seems to be easy but when it comes to the second step, applying the proper OOAD principles and design patterns is challenging.
  I took a look at couple of related questions like<br>
  <a href="https://stackoverflow.com/questions/5825619/shopping-cart-and-different-kinds-of-discounts-storing-discounts-in-db-and-appl">this one</a>. 
  But it did not help much.
  Appreciate any suggestions on how to go ahead.</p>
  
  <p>The code I could come up for the first step is :</p>
  
  <ol>
  <li><p>ShoppingCartTest.java :</p>
  
  <pre><code>public class ShoppingCartTest {
  
  ShoppingCart cart;
  
  @Before
  public void setUp(){
      cart = new ShoppingCart();
  }
  
  @Test
  public void addOneItemToCart() {
      cart.add("Bread");
      assertThat(cart.getTotalItems(), is(1));
      assertThat(cart.doesContain("Bread"), is(true));
  }
  
  @Test
  public void addTwoItemsToCart(){
      cart.add("Bread");
      cart.add("Milk");
      assertThat(cart.getTotalItems(), is(2));
      assertTrue(cart.doesContain("Bread"));
      assertTrue(cart.doesContain("Milk"));
  }
  
  @Test
  public void addThreeItemsToCart(){
      cart.add("Bread");
      cart.add("Milk");
      cart.add("Banana");
      assertThat(cart.getTotalItems(), is(3));
      assertTrue(cart.doesContain("Bread"));
      assertTrue(cart.doesContain("Milk"));
      assertTrue(cart.doesContain("Banana"));
  }
  
  @Test
  public void addAnItemTwice(){
      cart.add("Bread");
      cart.add("Bread");
      assertThat(cart.getTotalItems(), is(2));
  }
  
  @Test
  public void checkOutOneItem(){
      cart.add("Bread");
      assertThat(cart.checkout(), is(1.0));
  }
  
  @Test
  public void checkoutTwoSeparateItems(){
      cart.add("Bread");
      cart.add("Milk");
      assertThat(cart.checkout(), is(1.60));
  }
  
  @Test
  public void checkoutThreeSeparateItems(){
      cart.add("Bread");
      cart.add("Milk");
      cart.add("Banana");
      assertThat(cart.checkout(), is(2.0));
  }
  
  @Test
  public void checkoutTwoSameItems(){
      cart.add("Bread");
      cart.add("Bread");
      assertThat(cart.checkout(), is(2.0));
  }
  
  @Test
  public void checkoutThreeItems(){
      cart.add("Bread");
      cart.add("Bread");
      cart.add("Milk");
      assertThat(cart.checkout(), is(2.6));
  }
  
  @Test
  public void checkoutManyItems(){
      cart.add("Bread");
      cart.add("Bread");
      cart.add("Milk");
      cart.add("Milk");
      cart.add("Banana");
      assertThat(cart.checkout(), is(3.60));
  }
  
  @Test 
  public void checkOutAnInvalidItem(){
      cart.add("InvalidItem");
      assertThat(cart.checkout(),is(0.0));
  }}
  </code></pre></li>
  </ol>
  
  <p>Shopping Cart.java:</p>
  
  <pre><code>import java.util.ArrayList;
  import java.util.List;
  
  public class ShoppingCart {
  
  List&lt;String&gt; items;
  
  public ShoppingCart(){
      items = new ArrayList&lt;String&gt;();
  }
  
  public void add(String item) {
      items.add(item);
  }
  
  public int getTotalItems() {
      return items.size();
  }
  
  public Boolean doesContain(String itemName) {
      return items.contains(itemName);
  }
  
  public Double checkout() {
      double total = 0;
      for(String item: items){
          if(item.equals("Bread")){
              total += 1;
          }else if(item.equals("Milk")){
              total += 0.6;
          }else if(item.equals("Banana")){
              total += 0.4;
          }
      }
      return total;
  }   
  
  }
  </code></pre>