Sunday, March 6, 2011

Solving the supermarket coding kata using TDD – Part 2

The supermarket coding kata problem domain deals with the scenario of pricing goods at supermarkets. The scenario handles situations like.
Items in supermarket have simple prices, e.g. One Gatorade for $4.5. Other items may have complex prices like three for dollar or $3 for one pound etc.
In the previous post we’ve implemented the Item class and the tests for testing the functionality of the Item object. We’ll continue working on the sample and now try to implement the different pricing strategies on the items.
·         Create a new class in the test project and name it CountBasedPricingStrategy_Fixture
·         Add the test method to check the functionality of calculating the cost of items that have the pricing strategy based in number of items. E.g. Three for a dollar.
[TestMethod]
public void PricingStrategy_based_on_items_count_should_return_unitprice_based_on_the_parameters_passed()
{
    int itemCount = 3;
    decimal totalPrice = 1.00M;
    PricingStrategy countBasedPricingStrategy = new CountBasedPricingStrategy(itemCount, totalPrice);

    Item item = new Item("Original Glazed Donuts");
    item.SetPricingStrategy(countBasedPricingStrategy);
    decimal itemPrice = item.GetPrice();

    decimal expectedPrice = totalPrice / itemCount;
    Assert.AreEqual(expectedPrice, itemPrice);
}

·         As in the previous steps use the refactoring tool to generate the new class and the related methods. Run the test case and watch it fail.
·         Now implement the methods with the required functionality to make this test case pass.
public class CountBasedPricingStrategy : PricingStrategy
{
    private int _itemCount;
    private decimal _totalPrice;

    public CountBasedPricingStrategy(int itemCount, decimal totalPrice)
    {
        this._itemCount = itemCount;
        this._totalPrice = totalPrice;
    }

    public override decimal GetUnitPrice()
    {
        return _totalPrice / _itemCount;
    }
}

public abstract class PricingStrategy
{
    public abstract decimal GetUnitPrice();
}

·         As you can see I have abstracted the pricing calculation strategy to an abstract class and implemented the new class from the abstract class.
·         Similarly we can implement the other pricing strategies as given below.
[TestClass]
public class UnitPricingStrategy_Fixture
{
    [TestMethod]
    public void unit_pricing_strategy_returns_the_unitprice_for_the_item()
    {
        decimal unitPrice = 50M;
        UnitPricingStrategy unitPricingStrategy = new UnitPricingStrategy(unitPrice);

        Item item = new Item("Kellogs corn flakes");
        item.SetPricingStrategy(unitPricingStrategy);

        Assert.AreEqual(unitPrice, item.GetPrice());
    }
}

public class UnitPricingStrategy : PricingStrategy
{
    private decimal _unitPrice;

    public UnitPricingStrategy(decimal unitPrice)
    {
        this._unitPrice = unitPrice;
    }

    public override decimal GetUnitPrice()
    {
        return _unitPrice;
    }
}

[TestClass]
public class WeightBasedPricingStrategy_Fixture
{
    [TestMethod]
    public void items_price_should_differ_based_on_the_packed_weight()
    {
        decimal totalPrice = 99.99M;
        decimal baseWeight = 2M;

        decimal packetWeight = .5M;
        PackedWeightPricingStrategy priceWeightPricingStrategy = new PackedWeightPricingStrategy(totalPrice, baseWeight, packetWeight);

        Item item = new Item("Apple juice 2Ltr");
        item.SetPricingStrategy(priceWeightPricingStrategy);

        decimal expectedPrice = (totalPrice / baseWeight) * packetWeight;
        Assert.AreEqual(expectedPrice, item.GetPrice());
    }
}

public class PackedWeightPricingStrategy : PricingStrategy
{
    private decimal _totalPrice;
    private decimal _baseWeight;
    private decimal _packetWeight;

    public PackedWeightPricingStrategy(decimal totalPrice, decimal baseWeight, decimal packetWeight)
    {
        this._totalPrice = totalPrice;
        this._baseWeight = baseWeight;
        this._packetWeight = packetWeight;
    }

    public override decimal GetUnitPrice()
    {
        return (_totalPrice / _baseWeight) * _packetWeight;
    }
}

Next we’ll implement the checkout list and complete the first coding kata sample. Till then happy coding…