Welcome to your fourth unit for this course, dedicated to practicing Test-Driven Development (TDD), utilizing Ruby and RSpec. We're going to continue building our ShoppingCart
system by integrating even more features into our class.
In this course, the emphasis is on hands-on practice, where you'll receive requirements through tests, one at a time. Your task is to write tests AND implement code that makes each test pass, simulating a real-world TDD environment. Where I wrote the tests for you last time, this time it's all up to you!
Remember to use the core concepts of the Red-Green-Refactor cycle while completing these coding exercises. I'm still here to help! Just ask.
This section will cover additional features and enhancements for our ShoppingCart
class. As you write your test cases and implement the corresponding functionality, keep the requirements below in mind:
- Description: Removing an item that does not exist in the cart should raise an exception, indicating the item is not found.
- Details
- Support item removal through a
remove_item(item_id)
method. - Ensure the method raises an appropriate error message if an item does not exist in the cart.
- Support item removal through a
- Examples: Attempting to remove an item with
item_id: '999'
from the cart should raise an exception with the message'Item not found'
.
Ruby1class ShoppingCart 2 attr_reader :items 3 4 def initialize 5 @items = [] 6 end 7 8 # Existing methods ... 9 10 def remove_item(id) 11 item = @items.find { |i| i[:id] == id } 12 raise 'Item not found' unless item 13 14 if item[:quantity] > 1 15 item[:quantity] -= 1 16 else 17 @items.delete(item) 18 end 19 end 20end 21 22# Example usage 23cart = ShoppingCart.new 24begin 25 cart.remove_item('999') # Attempt to remove an item that doesn't exist 26rescue RuntimeError => e 27 puts e.message # Output: "Item not found" 28end
- Description: When a percentage discount is applied, the total price of the items in the cart should reflect this discount.
- Details
- Use the
apply_discount(percentage)
method to apply a percentage discount to the total. - Ensure
get_total()
returns the discounted price after applying the discount.
- Use the
- Examples: Applying a 10% discount to an item with a total price of
100
should result in a new total of90
.
Ruby1class ShoppingCart 2 # Existing methods ... 3 4 def apply_discount(percentage) 5 discount_factor = (100 - percentage) / 100.0 6 @discounted_total = total * discount_factor 7 end 8 9 def total 10 @discounted_total || @items.sum { |item| item[:price] * item[:quantity] } 11 end 12end 13 14# Example usage 15cart = ShoppingCart.new 16cart.add_item({ id: '1', name: 'Book', price: 100 }) 17cart.apply_discount(10) 18puts cart.total # Output: 90
- Description: When the total price of items in the cart exceeds $150, a bulk discount of 10% should be applied to the total.
- Details
- If the total exceeds 150, a 10% discount should be applied automatically.
- The
get_total()
method should return the discounted total when applicable.
- Examples: Adding an item
{ 'item_id': '1', 'name': 'Book', 'price': 200 }
should result in a total of180
after applying the bulk discount.
Ruby1class ShoppingCart 2 # Existing methods ... 3 4 def total 5 base_total = @items.sum { |item| item[:price] * item[:quantity] } 6 if base_total > 150 7 base_total * 0.9 8 else 9 base_total 10 end 11 end 12end 13 14# Example usage 15cart = ShoppingCart.new 16cart.add_item({ id: '1', name: 'Book', price: 200 }) 17puts cart.total # Output: 180
- Description: The cart should be able to remove all items, resetting the item count and total price to zero.
- Details
- Implement a
clear()
method to remove all items from the cart. - Ensure
get_item_count()
returns0
after clearing. - Verify
get_total()
is0
after clearing.
- Implement a
- Examples: If there are multiple items in the cart, calling
clear()
should leave the count as0
and the total as0
.
Ruby1class ShoppingCart 2 # Existing methods ... 3 4 def clear 5 @items.clear 6 end 7 8 def item_count 9 @items.sum { |item| item[:quantity] } 10 end 11end 12 13# Example usage 14cart = ShoppingCart.new 15cart.add_item({ id: '1', name: 'Book', price: 50 }) 16cart.clear 17puts cart.item_count # Output: 0 18puts cart.total # Output: 0
- Description: When the quantity of an item in the cart is updated, the item count and total price should reflect the updated quantity.
- Details
- Allow item quantities to be updated using an
update_quantity(item_id, quantity)
method. - Ensure
get_item_count()
returns the correct count after updating the quantity. - Update
get_total()
to return the correct total price after updating the quantity.
- Allow item quantities to be updated using an
- Examples: Updating the quantity of
{ 'item_id': '1', 'name': 'Book', 'price': 10 }
from2
to3
should result in a count of3
and a total of30
.
Ruby1class ShoppingCart 2 # Existing methods ... 3 4 def update_quantity(id, quantity) 5 item = @items.find { |i| i[:id] == id } 6 raise 'Item not found' unless item 7 8 item[:quantity] = quantity 9 end 10end 11 12# Example usage 13cart = ShoppingCart.new 14cart.add_item({ id: '1', name: 'Book', price: 10 }, 2) 15cart.update_quantity('1', 3) 16puts cart.item_count # Output: 3 17puts cart.total # Output: 30
In this unit, you explored the design of test cases for a new ShoppingCart
class, focusing on essential features like handling an empty cart, adding items, managing item quantities, and removing items. Now it’s your turn to ensure that the described functionality is implemented by writing comprehensive test cases and ensuring that the tests pass with the least amount of code using Ruby and RSpec.
As you undertake these exercises, remember to engage in the Red-Green-Refactor cycle. Be sure to practice writing tests first and do not write implementation code unless the test asks for it.
Red! Green! Refactor!