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
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 passes(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.
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.
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
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.
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 !!!