Click here to Skip to main content
15,884,472 members
Articles / TDD
Technical Blog

Test Driven Development (TDD) in Visual Studio 2012 using Stubs

Rate me:
Please Sign up or sign in to vote.
4.00/5 (1 vote)
9 Oct 2012CPOL4 min read 20.5K   7   2
Microsoft have introduced a whole bunch of features in Visual Studio 2012 that making unit testing a whole lot nicer, especially for agile and TDD.

Microsoft have introduced a whole bunch of features in Visual Studio 2012 that making unit testing a whole lot nicer, especially for agile and TDD.

  • Third-Party Testing Frameworks - allows developers to use whatever testing framework they want
  • Continuous Tests - feature to "Run Tests After Build"
  • Code Coverage - simplified the process and now also works with the 3rd party frameworks
  • Async tests - to test async methods
  • Javascript unit tests
  • C++ unit tests
  • Fakes - Stubs and Shims

Today I will be focusing on the use of Stubs, which is part of the Fakes framework. However, unfortunately, this is only available in VS2012 Ultimate. I am extremely disappointed in Microsoft for doing this as it makes the feature essentially useless. There are very few organizations that "only use Ultimate editions", and there is no upgrade path for those using VS2010 Moles.

Contract First

I'm going to start to implement a class which holds the balance for a person's bank account. I Start with the interface, and create a class which has the method but throws a not implemented exception. Its a good idea to start with a contract, which defines what you are trying to do: I want an object to store the balance of a person's bank account, and have the ability to update balance the balance by some value.

public interface IBalance
{
    decimal UpdateBalance(decimal value);
}

public class Balance : IBalance
{
    public decimal UpdateBalance(decimal value)
    {
        throw new NotImplementedException();
    }
}

It's not always possible to start with a contract, because you don't always know what you want to do and how best to structure a class. But that's OK, I recommend just getting something there and refactoring when you start writing unit tests and it becomes apparent you should structure your contract differently.

Test Driven

I then go to my test project, and start writing a test. This is how I will be calling the above class to update the balance.

[TestMethod]
public void TestUpdateBalance()
{
    //Arrange
    IBalance balance = new Balance();
    //todo: set the starting value of balance to 10

    //Act
    var actualBalance = balance.UpdateBalance(50);

    //Assert
    Assert.AreEqual(60, actualBalance);
}

When I build and run this test, it obviously fails with an expected NotImplementedException. Great, I have a failing test. I should write some implementation to make it pass.

As I'm about to implement the method, I realise I need to make a call out to a database. I will use a repository to do this, so I define a new interface with the methods I think I will need. But I'm not going to implement it just yet.

public interface IRepository
{
    void Update(decimal value);
    decimal GetBalance();
}

The idea is to use the repository pattern to create a repository (which is decoupled) and provides CRUD operations to the database. The repository class will need to be tested too, but not in the unit tests I'll be writing today. It will become part of an integration test suite because it will access the database.

I'll need to alter the test to take in the repository in the constructor of the Balance object. This is where I can use the Fakes framework.

Adding Fakes

To add the fakes assemblies, go to the references of the unit test project, right click the reference you want to create the fakes for, and in the context menu, select Add Fakes Assembly.

add-fakes

This will immediately add a reference to Microsoft.QualityTools.Testing.Fakes, and after a second or two, it will add a reference to a fake version of your assembly.

reference

Then we go back to our test code, and we can start updating our tests with a stub repository.

[TestMethod]
public void TestUpdateBalance()
{
    //Arrange
    decimal bal = 10;
    bool getBalanceWasCalled = false;
    bool updateDecimalWasCalled = false;

    IRepository repository = new MyClass.Fakes.StubIRepository()
                                 {
                                     GetBalance = () =>
                                                      {
                                                          getBalanceWasCalled = true;
                                                          return bal;
                                                      },
                                     UpdateDecimal = value =>
                                                         {
                                                             updateDecimalWasCalled = true;
                                                             bal = bal + value;
                                                         }

                                 };

    IBalance balance = new Balance(repository);

    //Act
    var actualBalance = balance.UpdateBalance(50);

    //Assert
    Assert.AreEqual(60, actualBalance);
    Assert.IsTrue(getBalanceWasCalled);
    Assert.IsTrue(updateDecimalWasCalled);
}

The generated fakes assembly has created Stub versions of my classes, both StubIRepository and StubIBalance is there, and I can create new instances of them. I can then stub out the public methods using delegates (lines 11-20).

Using variables which indicate whether the method was called is a pretty standard way of mocking objects, we are testing the implementation of the Balance class, not the implementation of the repository.

When I build and run the test, again it fails because of the exception, as expected.

Implementation!

And at this point, I'm ready to implement the Balance class to use the repository.

public class Balance : IBalance
{
    IRepository _repository;

    public Balance(IRepository repository)
    {
        _repository = repository;
    }
    public decimal UpdateBalance(decimal value)
    {
        //we should do validation first

        //and we should change this to be atomic

        _repository.Update(value);

        return _repository.GetBalance();
    }
}

Building this and re-running the test passes, yay!

Conclusion

This is a great feature from MS. No new syntax, supports delegates, and pretty quick and easy to get running.

The big bummer is, its only for Ultimate users (rich kids only) and that pretty much makes all of this useless right now. Hopefully we see it supported in more versions in SP1 and fully baked into VS2014

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMore features added in Visual Studio 2012 update1 Pin
Bandarupalli kalyan2-Jan-13 12:22
Bandarupalli kalyan2-Jan-13 12:22 
GeneralMy vote of 4 Pin
Victor_Gus21-Oct-12 0:31
Victor_Gus21-Oct-12 0:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.