Test Driven Development (TDD) in C#



There is such a great buzz about Test Driven Development(TDD) among the geeks and in the software industry that its being talked about in blog articles, conferences, code camps and so on and if as a developer you are not doing TDD you feel like you are doing something wrong and which in fact in the actual sense you are just writing legacy codes, shipping application full of bugs and doing everything wrong.

TDD is very important and is one of the great inventions in programming, it is now considered as one of the best practices in the software development. Doing TDD gives you satisfaction as a developer that you are building applications that are robust and perform what they are meant to do. Obviously codes written without tests will definitely generates bugs that will come back and hunt the programmer, thus precious development time will now be wasted on fixing bugs.

TDD is an iteration in which tests are written first and then codes to satisfy the tests. It can basically be summarised in four steps

Designing- this involves analysis and figuring out what is to be done
Testing
- writing a test to express the design(the test is expected to fail Test Failed because no code has been written yet)
Implementing- this involves writing the production codes required to satisfy the test
Testing- testing the code to ensure it passesTest Passed(if the test fails, then refactor the code until it passes the test)

To pratice TDD, a unit testing framework is needed. Visual Studio 2010 contains unit testing framework known as MSTest. There are other testing frameworks such as nUnit and MbUnit. I am more comfortable with nunit because it has come of age and is more matured. To download nunit go to the official site, the download contains the required libraries  and TestRunners(both console and GUI) needed for doing TDD.

Nunit relies heavily on attributes and assertions. Attributes are used to decorate classes, methods and properties, while assertions are central to unit testing frameworks, nunit has an Assert class with various static methods for doing the real testing.

In this article, the nunit attributes that we will be using are
[TestFixture]  - this is used to decorate a class and it indicates that a class contains tests.
[Test] - this is used to decorate a method and it indicates that a method is a test.
[TestFixtureSetUp] - when a method is decorated with this attribute, it is first executed prior to the execution of any test, usually this method is used for initialization, but if it fails or throws an exception, any other test will not be run in the test class.
[TestFixtureTearDown] - is used to decorate method used for cleaning up or freeing up resources in the TestFixture and it is run after all tests have been run.

Now with this pre-requisites known, lets do some coding, lets create a C# console application with a StringParser class,  the class contains a method GetNoofWordsInString that returns the number of words in a string and accepts a string argument.

Since we are doing TDD, we are going to write the test first before writing any code just like what the tenet of TDD says. So lets create a new console project and name it TDDExample, right click the project's solution and add another new project with the name TDDExample.Test the second project will house our test. It is a good practice to always seperate the Test-Project from the real Project being tested so as not to muddle up codes and so that tests are not deployed as part of an application during deployement.

TDDProjects

Now, lets write our test, right click the TDDExample.Test project and select Add Reference, browse to where you downloaded the nunit framework library to and select nunit.framework.dll also add a reference to the project to be tested in this case TDDExample then now add a new class to the test project and name it SentenceParserTest. This name indicates that it is a test for class SentenceParser. The full code listing of the class is below

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using TDDExample;

namespace TDDExample.Test
{
    [TestFixture]
    public class SentenceParserTest
    {
        SentenceParser sentenceParser;

        [TestFixtureSetUp]
        public void SetupTest()
        {
          sentenceParser = new SentenceParser();
        }

        [Test]
        public void TestGetNoofWordsInString()
        {
          string sentence = "coding is fun";
          // this contains three words,
           //we expect our code to return 3
          var noofWords=sentenceParser.GetNoofWordsInString(sentence);
          Assert.AreEqual(3, noofWords);
        }

        [TestFixtureTearDown]
        public void TearDownTest()
        {
          sentenceParser = null;
        }
    }
}

    

Looking at the codes, an object of the class SentenceParser was created in the class body, which was now initialized in the TestFixtureSetup, now our test is in the TestGetNoofWordsInString method, just as said earlier it is decorated with Test attribute. Note that all test methods have no return type and do not accept parameters. So we use the AreEqual static method of the Assert class, this helps us test our method's return value with the expected value.

The nunit test framework has both a console and a gui test runners, but I prefer the GUI test runner. Open the bin folder inside the nunit framework you downloaded and click the nunit.exe application to fire open the test runner. Build the TDDExample.Test and On the file menu of the nunit runner, click open project and locate the your test project built library inside the bin folder.

nunit gui test runner

Now, lets run the test, we expect the test to fail, because we have not yet written the codes to implement the GetNoofWordsInString in the TDDExample console application. Clicking the run button in the nunit test runner gives

test failed

Now lets, write codes to implement the GetNoofWordsInString in the TDDExample console application

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TDDExample
{
    public class SentenceParser
    {
        public int GetNoofWordsInString(string words)
        {
            int count = 1;
            int nextspaceposition=words.IndexOf(" ") ;
            while (nextspaceposition != -1 && words.Length!=0)
            {
                words = words.Remove(0, nextspaceposition+1);
                count++;
                nextspaceposition = words.IndexOf(" ");
            }
            return count;
        }
    }
}

The code returns the total words in a string passed into the method as parameter. If we now run the test, it will pass. But should in case it does not pass, then further refactoring is done until the code passes.

test failed

The full source code of this article can be downloaded here

Thus, if the codes is changed in future, with the test in place, it is run again to determine if nothing has been broken and that the code still does what it is meant to do.

Mastering TDD takes time, it might be time consuming in the beginning, but the time spent on testing a code is worth it and is better than spending time on fixing bug on an already deployed application.

Happy TDDing !!!




Share this page on


6 Comment(s)   12 People Like(s) This Page   Permalink  

 Click  To Like This Page

comments powered by Disqus



Older Comment(s)

Posted by    Rajesh Singh

Sunday, January 29, 2012    2:38 AM

Thanks alot.. Artical is very helpful. Can you please provide more details about the TDD?




Posted by    Ayobami Adewole

Sunday, January 29, 2012    4:13 PM

This is just an introductive article on TDD, I will provide more indept on advanced TDD concepts in my subsequent blog posts




Posted by    Ben

Sunday, January 29, 2012    11:56 PM

Thanks for taking the time to write on this valuable topic. FYI: TDD is not also called TFD. There is a big difference between the two patterns. TFD (Test First Development) only requires you to write the test before writing the code. You can put together a complete set of UML diagrams and still do TFD. You have created specifications for every Module/Class/Method/Property prior to writing




Posted by    Ayobami Adewole

Saturday, February 4, 2012    1:06 PM

@Ben, thanks for the observation/comment, I have edited the article and remove the reference to TFD




Posted by    Fab

Saturday, March 17, 2012    11:57 PM

to refactor means to change code so that it is easier to understand, or easier to maintain or has better performance, or has a better design , or is more robust etc, but it does not change what the code does. In other words, if the code is not working than one needs to fix it so it works, not refactor.




page