Test Driven Development in .NET

Test-Driven Development (TDD) is an approach for software development that says that we should write a test before writing a single line of code. This approach will force us to think about the requirements and how to validate the code against it. It also makes our code clean. If we write the code without testing then it will definitely generate bugs that would need to revisit the code to fix those bugs. According to “TDD is not about Testing”, TDD is a method of building the software with the functionality it actually needs and not with what the programmer thinks it probably would have. It might appear somewhat counter intuitive at the beginning, but it not only makes sense, it also quickly becomes a natural and elegant way to develop software.

Test-Driven Development revolves around a short iterative development cycle. It can basically be summarized in the following four steps:

  1. Write the tests for future code. We should include all possible combinations of inputs and outputs.

  2. Now write the code and run the test until it passes the tests already written.

  3. Now we need to refactor the code to increase the performance and readability. Once the refactoring is done we need to run the test once again to ensure nothing is breaking.

  4. Repeat these steps with other requirements.

Now we can say that TDD is a way to code what is needed, not what might be. TDD allows us to test quickly and efficiently the system after introducing any changes in existing functionality or a completely new function. It also allows a programmer to focus on the task at hand since the first goal is to make the test pass.

Visual Studio supports the concept of TDD through its unit testing framework. To show this I would create a Windows class library for performing math functions, such as addition and subtraction.

Create a blank solution and add a Class library as LibTDD. Now add a new unit test project to the solution file. It will add a class file to our unit test project as in the following:

  1. using System;  
  2. using Microsoft.VisualStudio.TestTools.UnitTesting;  
  3. namespace UnitTest   
  4. {  
  5.     [TestClass]  
  6.     public class UnitTest1   
  7.     {  
  8.         [TestMethod]  
  9.         public void TestMethod1() {}  
  10.     }  
  11. }  

Figure 1: Add New Project

Here we can see that every test class has an attribute as [TestClass]. Every test method must have the [TestMethod] attribute. The Test method must be void. It cannot take any parameter.

Now add a new class in the library project as clsMath with a method for add.
  1. public class clsMath   
  2. {  
  3.     public int Add(int a, int b)   
  4.     {  
  5.         throw new NotImplementedException();  
  6.     }  
  7. }
And modified the test method as:
  1. [TestClass]  
  2. public class UnitTest1   
  3. {  
  4.     [TestMethod]  
  5.     public void TestMethod1()   
  6.     {  
  7.         clsMath objMath = new clsMath();  
  8.         objMath.Add(10, 15);  
  9.     }  
  10. }
Now run the test. We can run the test using test menu.

Figure 2: Run the Test

Or by test explorer (select Test, Windows, then Test Explorer). Our test will fail since we don’t have any implementation in the function.

Figure 3: Test Explorer

Now change the add method as in the following:
  1. public int Add(int a , int b)  
  2. {  
  3.    return a + b;  
And run the test again.

Figure 4: Run the test Again

Now the new method in the library project is as in the following:
  1. public int Division(int a, int b)  
  2. {  
  3.    return a/b;  
  4. }
And add two new test methods as in the following:
  1. [TestMethod]  
  2. public void TestDivision1()   
  3. {  
  4.     clsMath objMath = new clsMath();  
  5.     objMath.Division(75, 15);  
  6. }  
  7. [TestMethod]  
  8. public void TestDivision2()   
  9. {  
  10.     clsMath objMath = new clsMath();  
  11.     objMath.Division(10, 0);  
  12. }
Now if we run the tests then TestDivision2 will fail and give a DivideByZeroException exception.

Figure 5: Test Division1

We can pass this test by either adding a new attribute to the test method as in the following:
  1. [ExpectedException(typeof(DivideByZeroException))]
Or with a try-catch in the Division method.

Now with the tag our test method would look such as in the following code snippet.
  1. [TestMethod]  
  2. [ExpectedException(typeof(DivideByZeroException))]  
  3. public void TestDivision2()  
  4. {  
  5.     clsMath objMath = new clsMath();  
  6.     objMath.Division(10, 0);  
  7. }

Figure 6: Test Division2