C# – TDD: Stub, Mock, or None of the Above

cmockingstubtdd

I'm trying to learn TDD by applying it to a simple project of mine. Some details (and an earlier question) are here:

TDD: Help with writing Testable Class

The specifics are I have a PurchaseOrderCollection class that has a private List of PurchaseOrders (passed in at constructor), and the PurchaseOrders have a boolean property IsValid. The PurchaseOrderCollection has a property HasErrors that returns a true if any PurchaseOrders in the list have IsValid as false. This is the logic I want to test.

[TestMethod]
public void Purchase_Order_Collection_Has_Errors_Is_True_If_Any_Purchase_Order_Has_Is_Valid_False()
{
    List<PurchaseOrder> orders = new List<PurchaseOrder>();

    orders.Add(new PurchaseOrder(--some values to generate IsValid false--));
    orders.Add(new PurchaseOrder(--some values to generate IsValid true--));

    PurchaseOrderCollection collection = new PurchaseOrderCollection(orders);

    Assert.IsTrue(collection.HasErrors);
}

This is similar to my previous question in that this test is too coupled in that I have to know the logic of what makes a PurchaseOrder IsValid false or true to pass the test, when really this test shouldn't care. The question is different (imo) in that the classes themselves aren't the problem.

Essentially I want to be able to declare a PurchaseOrder that has IsValid false or true without knowing anything more about what a PurchaseOrder is.

From my limited TDD knowledge, this is something you use Stubs or Mocks for. My main question, is this correct? Or should I be using a different method for this? Or am I completely flawed and am just writing this test and thinking about it wrong?

My initial thought was to just use some kind of mock framework and create a PurchaseOrder that always returns true or false. From what I've read though, I'd need to declare IsValid virtual. So my second thought was to change it to add IPurchaseOrder as an interface for PurchaseOrder and just create a fake PurchaseOrder that always returns false or true. Are both of these valid ideas?

Thanks!

Best Answer

You are on the right track with either creating a stub or a mock. I prefer using a Mocking framework.

How it would work using a mocking framework is that you would want to mock your PurchaseOrder class therefore abstracting away it's implementation. Then setup expectations that IsValid is called and when it is called return this value.

Example using Moq, if you're using C# 3.0 and .NET Framework 3.5:

[TestMethod]
public void Purchase_Order_Collection_Has_Errors_Is_True_If_Any_Purchase_Order_Has_Is_Valid_False()
{    
    var mockFirstPurchaseOrder = new Mock<IPurchaseOrder>();
    var mockSecondPurchaseOrder = new Mock<IPurchaseOrder>();

    mockFirstPurchaseOrder.Expect(p => p.IsValid).Returns(false).AtMostOnce();
    mockSecondPurchaseOrder.Expect(p => p.IsValid).Returns(true).AtMostOnce();

    List<IPurchaseOrder> purchaseOrders = new List<IPurchaseOrder>();
    purchaseOrders.Add(mockFirstPurchaseOrder.Object);
    purchaseOrders.Add(mockSecondPurchaseOrder.Object);

    PurchaseOrderCollection collection = new PurchaseOrderCollection(orders);

    Assert.IsTrue(collection.HasErrors);
}

Edit:
Here I used an interface to create the mock of PurchaseOrder, but you don't have too. You could mark IsValid as virtual and mock the PurchaseOrder class. My rule of thumb when which way to go is to use virtual first. Just to create an interface, so I can mock an object without any architectual reason is a code smell to me.