Inside TFS

Step-By-Step Test-Driven-Development with Visual Studio 2012: Part 1

Test-driven development has been enhanced with Visual Studio 2012; learn how to use this powerful tool by building a class library for math functions.

Click here for Part 2

(This article applies to all editions of Visual Studio 2012, except Test Professional 2012)

There are various ways to build and test software. The specific process followed depends on a variety of factors, including the project itself, team members, project schedule and so on. One such process is termed Test-driven Development (TDD). In TDD, I develop test cases before I write any code. Once I have test cases in place, then I can build the appropriate functionality to make the tests pass.

This is a reverse of the standard coding model, where code is developed first, then tested. But this method has several benefits:

  • The ability to tackle small aspects of the system initially, and evolve the system as the requirements evolve
  • The tests act as documentation for the system
  • The tests serve as a suite of regression tests, ensuring that future code changes don't break existing functionality

Visual Studio 2012 supports the concept of TDD through its unit testing framework. In this column, I'll walk through a simple example of using Visual Studio 2012, and its unit testing framework, to perform TDD. My scenario is building a windows class library for performing math functions, such as addition and subtraction.

To begin, create a blank solution in Visual Studio 2012 named ALM.UnitTestingExample. Add a new C# Windows Class Library project to the solution, and name it ALM.MathLibrary. This project will contain the code for performing the math functions. Now add a C# Windows Unit Test Project to the solution, and name it ALM.MathLibraryTests. A Test Project is a Visual Studio project that contains various tests, such as unit tests and web tests, and will contain the tests designed for the math library. Delete the Class1.cs file from the ALM.MathLibary project, and the UnitTest1.cs file from the ALM.MathLibraryTests project. Finally, add a reference to the ALM.MathLibrary project, from the ALM.MathLibraryTests project.

With the base solution now in place, I can start building the tests. This is a math library which will have functions for addition and subtraction. Right-click on the ALM.MathLibraryTests project, and select Add | New Item. Select the Unit Test object, and name it BasicMathFunctionsTest.cs. This creates a new class file to contain all tests related to basic math functions. Figure 1 shows what the base generated code for this class looks like.

[Click on image for larger view.] Figure 1. The base generated code for a unit test.

Notice the different attributes in the code. Above the class declaration is a [TestClass] attribute. This marks this class as a test class containing test methods, which allows the unit testing framework to pick it up.  The generated code also created a sample test method for me, named TestMethod1. This method is also marked with an attribute, [TestMethod]. This attribute allows the testing framework to identify this method as a potential test that needs to be run. Rename TestMethod1 to be AddTest. Right-click on the solution in Solution Explorer and select Build Solution to verify the solution will build.

At this point I have a test project, with a test class and a blank test method. Just for fun, let's run this test and see what happens. Visual Studio 2012 has a window called Test Explorer for interacting and running unit tests. In Visual Studio, select Test | Windows | Test Explorer to open this window, shown in Figure 2.

Figure 2. The AddTest Method, with test code added.

When the test project was compiled, the testing framework found the test class and method definitions, and displays the tests in the Test Explorer window. In this scenario, it knows this test has not been run yet, so it lists it under the Not Run Tests category. There are multiple options for running tests. I can right-click on a specific test and run just that test. I can run an entire category of tests. Or I can run all the tests listed in the Test Explorer. Click the Run All link to run all the tests. The solution will be built, and the test will run, with the results showing at the bottom of the test window. In this scenario, the test will pass, as there's no actual test to run. Notice also that the test was moved to the Passed Tests category in Test Explorer.

Now let's build an actual test. As Figure 3 shows, I've added code to the AddTest method.

[Click on image for larger view.] Figure 3. The AddTest Method, with test code added.

For this test, I'm instantiating a class called BasicMathLibrary. I'm going to be testing the Add function of the library, so I specify the expected value, then make a call to the Add method. Finally, I use the Assert.AreEqual method to check whether or not the expected value matches the actual value returned from the Add method. However, if I build the solution, the build will fail (obviously) because I haven't created the BasicMathLibrary class or the Add method. So, following test-driven development principals, I should create the class and the method, as shown in Figure 4.

[Click on image for larger view.] Figure 4. The created class and method, based off the test code.

Notice how I've created the BasicMathLibrary class and the Add method, but haven't built any functionality yet for the Add method. Instead, I am throwing a NotImplementedException exception. This allows me to quickly stub out methods without adding actual logic, to allow my solution and tests to compile.

With the class and method stubbed out, build the solution again. At this point, the solution should compile correctly. Go back to the Test Explorer and click the Run All link. The AddTest will run, and this time will fail, as shown in Figure 5.

[Click on image for larger view.] Figure 5. The Test Explorer window, showing that the AddTest test has failed.

Figure 5 shows the AddTest unit test failed, and gives me details around the failure. In this instance, it tells me that the method or operation isn't implemented, which is what was expected.  From here, I can go back to the Add method, implement the appropriate code, then re-run the test. Once that test passes, I create the next unit test, and then go through the same process as outlined earlier.

TDD is a proven methodology for building software that helps ensure the source code is thoroughly unit tested. And Visual Studio 2012, with its unit testing framework, provides the ability to easily implement test-driven development in an organization. In Part 2 of this column, I will continue to build off this example, and show in more detail how to use the unit test framework in Visual Studio 2012.

About the Author

Mickey Gousset spends his days as a principal consultant for Infront Consulting Group. Gousset is lead author of "Professional Application Lifecycle Management with Visual Studio 2012" (Wrox, 2012) and frequents the speaker circuit singing the praises of ALM and DevOps. He also blogs at ALM Rocks!. Gousset is one of the original Team System/ALM MVPs and has held the award since 2005.

comments powered by Disqus


  • 'Dev Home' Update Leads Developer Goodies in AI-Powered Windows 11 Update

    Along with today's new AI-powered Windows 11 update come new goodies for developers, including a new edition of Dev Home, a preview offering described as a "control center" providing coding-focused features and functionality.

  • Community Dev Gives VS Code Python Some YAPF

    The latest update to Python in Visual Studio Code includes a new extension for Python formatting that was contributed by a member of the open source community.

  • Devs Demand Visual Studio 2022 Ditch Old .NET Framework Dependencies

    Developers commenting on a Microsoft post about performance improvements in the upcoming .NET 8 demanded the company end Visual Studio 2022's dependency on the old .NET Framework.

  • Microsoft Remakes Azure Quantum Dev Kit with Rust, 'and It Runs in the Browser!'

    "The' tl;dr' is that we rewrote it (mostly) in Rust which compiles to WebAssembly for VS Code or the web, and to native binaries for Python."

Subscribe on YouTube