Test: Buy 2 Get 1
In the next requirement, we need to use an external service, IOfferService
, to determine eligibility for the "Buy 2 Get 1 Free" offer for certain items only. This will affect how the totals are calculated.
Step 1: Create the interface IOfferService
public interface IOfferService
{
bool IsEligibleForBuyTwoGetOne(string itemName);
}
Step 2: Write the Failing Test Case
Write a test case to verify that the offer is correctly applied using the IOfferService
. Note that a mocking framework should be used to mock the IOfferService
behavior.
Test Case Setup:
Add a reference to a mocking library (like Moq) if not already added.
Modify the test constructor to now make use of new cart constructor which uses a service.
public class ShoppingCartTests
{
private readonly ShoppingCart _cart;
private readonly Mock<IOfferService> _mockOfferService;;
//xUnit creates a new instance of the test class for each test, so it is safe to share context!
public ShoppingCartTests()
{
_mockOfferService = new Mock<IOfferService>();
_cart = new ShoppingCart(_mockOfferService.Object);
}
//other code...
}
Step 3: Write test case
[Fact]
public void Apply_BuyTwoGetOneFreeOffer_WhenEligible()
{
var itemName = "apple";
var quantity = 3;
var price = 1.00;
var isEligible = true;
var expectedTotal = 2.00;
_mockOfferService.Setup(s => s.IsEligibleForBuyTwoGetOne(itemName)).Returns(isEligible);
_cart.AddItem(new Item(itemName, quantity, price));
var total = _cart.CalculateTotalCost();
total.Should().Be(expectedTotal);
}
Step 4: Modify the ShoppingCart (just to provision for enabling Injection of the service)
Guidance: Modify the
ShoppingCart
class to accept anIOfferService
instance via constructor injection. Initially, do not change any logic in the methods.Code:
public class ShoppingCart { private readonly IOfferService _offerService; public ShoppingCart(IOfferService offerService) { _offerService = offerService; } // ... existing methods ... }
Step 5: Run the Test (Confirm Failure)
Action: Run the test to confirm it fails, as the logic to use the
IOfferService
is not implemented yet.
Step 6: Implement Logic to Pass the Test
Task: Implement the logic in the
ShoppingCart
class to use theIOfferService
for determining offer eligibility.Guidance: Ensure that the
CalculateTotalCost
method utilizes theIOfferService
to apply discounts appropriately.
public class ShoppingCart
{
private readonly IOfferService _offerService;
public ShoppingCart(IOfferService offerService)
{
_offerService = offerService;
}
// ... existing methods ...
public double CalculateTotalCost()
{
double total = 0.0;
foreach (var item in Items)
{
bool isEligible = _offerService.IsEligibleForBuyTwoGetOne(item.Name);
if (isEligible && item.Quantity >= 3)
{
int freeItems = item.Quantity / 3;
total += (item.Quantity - freeItems) * item.Price;
}
else
{
total += item.Price * item.Quantity;
}
}
return total;
}
}
Step 7: Re-run the Test (Verify Success)
Action: Run the test again. The test should now pass, demonstrating that the shopping cart correctly interacts with the
IOfferService
.
Last updated