Jan 28, 2012. 7:30 PM
There is such a great buzz about Test Driven Development(TDD) also known as Test First Development(TFD) among the geeks and in the software industry that it's 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 code written without tests will definitely generates bugs that will come back and haunt 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 code 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 because no code has been written yet).
- Implementing - This involves writing the production code required to satisfy the test.
- Testing - Testing the code to ensure it passes(if the test fails, then refactor the code until it passes the test).
To practice 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 these pre-requisites known, let's do some coding. Let's 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 let's 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 separate the Test-Project from the real Project being tested so as not to muddle up code and so that tests are not deployed as part of an application during deployment.
Now, let's 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";
var noofWords = sentenceParser.GetNoofWordsInString(sentence);
Assert.AreEqual(3, noofWords);
}
[TestFixtureTearDown]
public void TearDownTest()
{
sentenceParser = null;
}
}
}
Looking at the code, 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.
Now, let's run the test, we expect the test to fail, because we have not yet written the code to implement the GetNoofWordsInString
in the TDDExample
console application. Clicking the run button in the nunit test runner gives:
Now let's write code 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 if in case it does not pass, then further refactoring is done until the code passes.
The full source code of this article can be downloaded here.
Thus, if the code 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 !!!