In this post I am going to show you the thought process and steps that I take while doing TDD. I am going to focus on a simple scenario to show you the baby steps that I take while writing my unit tests. This is going to be a two part tutorial. In this first part I am going to show you how to follow the 3 step process of TDD i.e. Red, Green & Refactor. I am going to write a few basic tests for a Shopping Cart. In part two I will add further tests that require me to use mocking. During this tutorial, I will be thinking out loud so that you can understand how I tempt the urge to jump ahead at times and stick to what TDD defines.

I want to write code for the following functionality in my cart.

  • Add and item to cart
  • Remove an Item from cart
  • Add an item multiple times to the cart
  • Handle adding an Item that is out of stock

Let’s Code

Open up Visual Studio and create a new blank solution. Now add a class library and name it “ShoppingCart”. Next lets add project for our unit tests. Add a new “Unit Test Project” and name it “ShoppingCart.Tests”. Our production code is going to reside in the ShoppingCart project whereas all the tests are going to be in the ShoppingCart.Tests project. The first test that I want to write is for adding an item to an empty cart. Create a class “CartTests” in the test project and add the following code to it.

        [TestMethod];
        public void Add_AddingItemToEmptyCart_CountShouldBeOne()
        {
            // Arrange
            var cart = new Cart();
            var item = new CartItem {Sku = "123", Name = "Softdrink", Price = 1.00};

            // Act
            cart.Add(item);

            // Assert
            Assert.AreEqual(1, cart.Count);
        }

Notice the name of my test, your unit tests should ideally communicate three things to its reader. The name of the method that your are testing, the context in which you are executing your unit test and the expected outcome of the test. If you provide these three pieces of information in your unit test then it will be very clear to a future developer who is reading it that what is your unit test testing.

At this point in time if I try to build the code it will fail because I do not have Cart & CartItem classes in my project. Now I need to create these classes so that the code can build. I am using Resharper which makes it a breeze to refactor code; using it I can generate both the classes and their required method and properties. Here are my generated classes.


    public class Cart
    {
        public void Add(CartItem item)
        {
            throw new NotImplementedException();
        }

        public int Count { get; set; }
    }

    public class CartItem
    {
        public string Sku { get; set; }
        public string Name { get; set; }
        public double Price { get; set; }
    }

Now I can build my solution but if I run my test it fails. I have achieved the Red part of the TDD cycle, my test is failing. Now I need to make my test pass and I will only write enough code to make it pass. How about this?


    public class Cart
    {
        public void Add(CartItem item)
        {

        }

        public int Count
        {
            get { return 1; }
        }
    }

Voilà my test passes! At this point you might start wondering if I am insane, but remember the most important rule of TDD is that you let your tests drive your code and you only write enough code to make our tests pass. In this case all I need to make the test pass is to return 1 from my Count property. Notice I now have a blank Add method and just changed the Count property to a readonly Property that returns 1. I know that this code is not right but in order to prove it wrong I have to write a failing test 🙂 so let’s continue.


        [TestMethod]
        public void Add_AddingItemToEmptyCart_TotalShouldBeThePriceOfTheItem()
        {
            // Arrange
            var cart = new Cart();
            var item = new CartItem { Sku = "123", Name = "Softdrink", Price = 1.00 };

            // Act
            cart.Add(item);

            // Assert
            Assert.AreEqual(1, cart.Total);
        }

My second test simply tests that when I add only 1 item to the cart, the total of the cart should equal the price of the item. Now my code will not compile at this point as I do not have the Total property in the Cart class. After we create the Total property and run our test our test fails.

Failing Test

Fig-01: Total returned is incorrect

As you can see the expected result was 1 but the actual value of total was 0. Let’s write code to make the test pass. Remember I have to write the simplest code possible to make both the test pass.


    public class Cart
    {
        public void Add(CartItem item)
        {

        }

        public int Count
        {
            get { return 1; }
        }

        public double Total
        {
            get { return 1; }
        }
    }

Again I used the same method to make my test pass, just return hard coded value. This makes both our tests pass. Now I know that this code is incorrect but I will have to make a test prove it first. Now let’s see if I need to refactor this code? Remember TDD is a 3 step iteration process Red, Green & Refactor. I have first made sure that my tests fail, then I have only written enough code to make them pass and after writing each code I need to see if I need to do any refactoring.

One practice that I use when I write unit tests is to create a factory class or separate method for creation of classes. You can already see that almost every test we write for the Cart class, we will need to create an instance of it. What happens if we have written 100 tests and then in future we need to modify the constructor? If you have not separated out the creation of cart object in a separate method or class, you will end up having to change all the tests that you have written which is a maintenance overhead. I am just going to extract out the creation of cart class in a separate method for now which might seem completely unnecessary at the moment but I know it is extremely useful. So lets refactor the code and create a method for creation of the Cart object.


    [TestClass]
    public class ShoppingCartTests
    {
        private Cart CreateEmptyCart()
        {
            return new Cart();
        }

        [TestMethod]
        public void Add_AddingItemToEmptyCart_CountShouldBeOne()
        {
            // Arrange
            var cart = CreateEmptyCart();
            var item = new CartItem { Sku = "123", Name = "Softdrink", Price = 1.00 };

            // Act
            cart.Add(item);

            // Assert
            Assert.AreEqual(1, cart.Count);
        }

        [TestMethod]
        public void Add_AddingItemToEmptyCart_TotalShouldBeThePriceOfTheItem()
        {
            // Arrange
            var cart = CreateEmptyCart();
            var item = new CartItem { Sku = "123", Name = "Softdrink", Price = 1.00 };

            // Act
            cart.Add(item);

            // Assert
            Assert.AreEqual(1, cart.Total);
        }
    }

Now I will rerun all the test to make sure that they pass and sure enough they do.

All tests pass

Fig-02: All tests pass

Now I will add a test to verify that if I add two items to an empty cart, its count should be 2


        [TestMethod]
        public void Add_AddingTwoItemsToEmptyCart_CountShouldBeTwo()
        {
            // Arrange
            var cart = CreateEmptyCart();
            var item1 = new CartItem { Sku = "123", Name = "Softdrink", Price = 1.00 };
            var item2 = new CartItem { Sku = "456", Name = "Fresh Juice", Price = 1.00 };

            // Act
            cart.Add(item1);
            cart.Add(item2);

            // Assert
            Assert.AreEqual(2, cart.Count);
        }

I run the test and surely it fails.

Item count is invalid

Fig-03: Item count is invalid

Now let’s make this test pass.


    public class Cart
    {
        private readonly List<CartItem> _Items;

        public Cart()
        {
            _Items = new List<CartItem>();
        }

        public void Add(CartItem item)
        {
            _Items.Add(item);
        }

        public int Count
        {
            get { return _Items.Count; }
        }

        public double Total
        {
            get { return 1; }
        }
    }

All tests pass

Fig-04: All tests pass

Now you can see how this test has forced me to write the correct implementation for the Cart class. I can no longer continue to make all my tests pass without correcting the logic inside my Cart class. The Total property however is still returning a hard coded count but you can guess that the next test will force me to make it right!. At this point my code is pretty clean and I don’t think we need to do any refactoring so let’s write the next test.


        [TestMethod]
        public void Add_AddingTwoItemsToEmptyCart_TotalShouldBeTheCorrect()
        {
            // Arrange
            var cart = CreateEmptyCart();
            var item1 = new CartItem { Sku = "123", Name = "Softdrink", Price = 1.00 };
            var item2 = new CartItem { Sku = "456", Name = "Fresh Juice", Price = 2.00 };

            // Act
            cart.Add(item1);
            cart.Add(item2);

            // Assert
            Assert.AreEqual(3, cart.Total);
        }

When I run the test it sure enough fails.

Total is incorrect

Fig-05: Total is incorrect

Now I will fix my code


    public class Cart
    {
        private readonly List<CartItem> _Items;

        public Cart()
        {
            _Items = new List<CartItem>();
        }

        public void Add(CartItem item)
        {
            _Items.Add(item);
        }

        public int Count
        {
            get { return _Items.Count; }
        }

        public double Total
        {
            get { return _Items.Sum(i => i.Price); }
        }

Now if I run the test it passes. Let’s run all the tests to make sure that they all pass.

All tests pass

Fig-06: All tests pass

Here is the complete code that I have up till this point


    [TestClass]
    public class CartTests
    {
        private Cart CreateEmptyCart()
        {
            return new Cart();
        }

        [TestMethod]
        public void Add_AddingItemToEmptyCart_CountShouldBeOne()
        {
            // Arrange
            var cart = CreateEmptyCart();
            var item = new CartItem { Sku = "123", Name = "Softdrink", Price = 1.00 };

            // Act
            cart.Add(item);

            // Assert
            Assert.AreEqual(1, cart.Count);
        }

        [TestMethod]
        public void Add_AddingItemToEmptyCart_TotalShouldBeThePriceOfTheItem()
        {
            // Arrange
            var cart = CreateEmptyCart();
            var item = new CartItem { Sku = "123", Name = "Softdrink", Price = 1.00 };

            // Act
            cart.Add(item);

            // Assert
            Assert.AreEqual(1, cart.Total);
        }

        [TestMethod]
        public void Add_AddingTwoItemsToEmptyCart_CountShouldBeTwo()
        {
            // Arrange
            var cart = CreateEmptyCart();
            var item1 = new CartItem { Sku = "123", Name = "Softdrink", Price = 1.00 };
            var item2 = new CartItem { Sku = "456", Name = "Fresh Juice", Price = 1.00 };

            // Act
            cart.Add(item1);
            cart.Add(item2);

            // Assert
            Assert.AreEqual(2, cart.Count);
        }

        [TestMethod]
        public void Add_AddingTwoItemsToEmptyCart_TotalShouldBeCorrect()
        {
            // Arrange
            var cart = CreateEmptyCart();
            var item1 = new CartItem { Sku = "123", Name = "Softdrink", Price = 1.00 };
            var item2 = new CartItem { Sku = "456", Name = "Fresh Juice", Price = 2.00 };

            // Act
            cart.Add(item1);
            cart.Add(item2);

            // Assert
            Assert.AreEqual(3, cart.Total);
        }
    }

    public class CartItem
    {
        public string Sku { get; set; }
        public string Name { get; set; }
        public double Price { get; set; }
    }

    public class Cart
    {
        private readonly List<CartItem> _Items;

        public Cart()
        {
            _Items = new List<CartItem>();
        }

        public void Add(CartItem item)
        {
            _Items.Add(item);
        }

        public int Count
        {
            get { return _Items.Count; }
        }

        public double Total
        {
            get { return _Items.Sum(i => i.Price); }
        }
    }

The important thing to learn when getting started with TDD is that you have to strictly follow the rules of TDD and do not need to jump ahead to write extra code. When you know that your code is incorrect, just write a failing test to prove it and then make the test pass. Continuously refactor your code and try to separate out logic for creation of objects as you might need to change it later at some stage. TDD can be a bit challenging for beginners but you only need some time to get the hang of it and then you will start seeing the benefits that it has to offer. In the next tutorial I will continue to add to this code and implement the rest of the tests. Till then Happy Coding!