Click here to Skip to main content
Click here to Skip to main content

Tagged as

Go to top

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

, 9 Oct 2012
Rate this:
Please Sign up or sign in to vote.
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 wantContinuous Tests - feature to "Run Tests After Build"Code

Editorial Note

This article appears in the Third Party Product Reviews section. Articles in this section are for the members only and must not be used by tool vendors to promote or advertise products in any way, shape or form. Please report any spam or advertising.

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)

Share

About the Author

EdmundYeung

United States United States
No Biography provided

Comments and Discussions

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

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.140905.1 | Last Updated 9 Oct 2012
Article Copyright 2012 by EdmundYeung
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid