Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Introduction to NUnit and TDD

4.81/5 (39 votes)
25 Feb 2011CPOL7 min read 117.5K  
This is an introduction to NUnit and TDD

Introduction

NUnit is a great unit testing tool for .NET applications. In this article, I will explain the basics of NUnit, and guide you step by step to creating sample unit tests. But, if unit testing is what you are looking for, you should also know the concept of Test Driven Development. It is also the other way round, if TDD is your aim, you must glance at NUnit too. To truly exploit the benefits of unit testing, TDD is the best approach. So this article also covers the TDD concept.

What is Unit Testing

Unit testing is a development procedure where programmers create tests as they develop software. The tests are simple short tests that test functionality of a particular unit or module of their code, such as a class or function. The general behavior of an unit test is that it sends a predefined message to the class and verifies the response. Yes, you heard it correct! Developers are responsible for unit testing, and which means you have to code extra! Some 20% extra ! Hold on, the benefits are much more.

Let's Understand NUnit First

NUnit is an unit testing framework, developed using C#. It uses attribute based programming model. It provides a nice clean GUI as well as console application to test your assemblies. We will look into it a bit later. First let us create a sample test.

Here I have taken an example of Person class. So create the following class in a project.

C#
public class Person
    {
        public string Lname
        { get; set; }

        public string Fname
        { get; set; }

        public string Mname
        { get; set; }

        public string Address
        { get; set; }

        public string Email
        { get; set; }

        public string Phone
        { get; set; }


        public string GetFullName()
        {
            if(string.IsNullOrEmpty(Lname))
                throw new MissingFieldException("Lname is empty");

            return string.Format("{0} {1} {2}",Fname,Mname,Lname);
        }
    }

Step 1: Add reference to nunit.framework.dll from the bin of installed nunit application.

Step 2: Create a class to write your tests. Say you want to test a “Person” class. Name your test class as TestPerson. Best Practice: Use a separate class library. Have separate classes to test each class in your application.

Step 3: Add Attribute to Class.

The test class should have the “Test Fixture” attribute.

Let's understand this attribute:

C#
[TestFixture]
  • The class that is going to contain your code for testing should be attributed with this attribute.
  • When you attach this attribute to a class in your project, the Test Runner application will scan it for test methods.
  • The class must have a public default constructor.

Code Snippet

C#
[TestFixture]
public class TestPerson 

Step 4: Write test

Create a method named testFullName(). This is the method that will contain code to test the “GetFullName()” method.

This method should be marked with Attribute [Test]. Any method that has the actual code to perform test should be marked with this attribute. The signature should necessarily be: public void <methodname />().

Now, implement the following code in the method:

C#
using NUnit.Framework;

namespace NunitExample
{
    [TestFixture]
    public class TestPerson
    {

        [Test]
        public void TestFullName()
        {
            
            Person person = new Person ();
    		 person.lname = "Doe";
            person.mname = "Roe";
            person.fname = "John";

            string actual = person.GetFullName();
            string expected = "John Roe Doe";
            Assert.AreEqual(expected, actual,
		"The GetFullName returned a different Value");
        }
    }
}

Let us understand the code: The test method assigns fixed values to the properties of class Person. Now we want to check that GetFullName() functions correctly. So we compare the returned value with what we expected. If that matches, the test passes or else the test fails.

To compare the results, we use the “Assert” class of Nunit Framework. Assertions are central to any unit testing framework. Here, we use “AreEqual” method to compare the two results.

As seen, the AreEqual() expects 3 parameters. The third is optional. The first two are the values that we want to compare, and the third is the message to be displayed when the test fails.

There are many overloads of AreEqual method, so that you can compare different datatypes.

There are many different methods of Assert class, to support collections, exceptions, directories, files, etc. We will not cover all of them here. You can easily get an idea of all these on the official Nunit Site.

Step 5: Run the code.

Compile your code.

Let us use the GUI to run the code. Open the GUI, and select “New project” from file menu. Save the new project some name.

Then go to project menu and select “Add Assembly” and select the assembly which contains your test class. You will see that the test class and its test methods are displayed on the left panel of the window.

Select the PersonTest class, and click on Run. All the test within this class will be run.

2-25-2011_11-31-13_AM.png

When you see all green out there, it's party time! All your tests have passed. When you examine the screen in detail, you will that it displays various parameters like what tests have passed, failed, the time taken to execute a test, etc.

Now change the above code in the test method, to get invalid result. Some like:

C#
Assert.AreEqual("abcd", "actual" ,"The GetFullName returned a different Value"). 

Rebuild the assembly, and in the Nunit GUI, click on File->Reload tests.

Now, run again, just to see, how the screen looks when the test fails.

failed.png

See the red, it also displays the message you specified.

Fine, now you know how to run and code your unit tests. Let have a quick glance at few other important and very useful attributes.

Some Important Attributes

Setup Attribute

C#
[SetUp]
public void init()
{
    Person person = new Person();
}

As you can see in the code, the Setup attribute should be used for any initialization kind of functions. Any code that must be executed prior to executing a test can be put in the functions marked with [Setup]. This frees you from repeating these lines of code in each test. Please note carefully, that this code is executed, before each test.

Tear Down

This attribute is exactly opposite to Setup Attribute. This code is executed after execution of each code. In this method, for example, you can write code, to close any FileSystem Object or Database connection.

Exception Expected

At times, we may want to test that a method should throw an exception in a particular scenario. We can test this using this attribute.
Example:

C#
[Test]
[ExpectedException(typeof(MissingFieldException))]
public void TestFullNameForException()
{
    Person person = new Person();
    person.Lname = "";
    person.Mname = "Roe";
    person.Fname = "John";

    string actual = person.GetFullName();
}

This code does not have any Assert statement. This will pass if the “MissingFieldException” in thrown upon calling “GetFullName()”. If no exception is thrown, the test will fail.

Ignore

Any test that you want to temporarily bypass can be marked with this attribute.

Some Obvious Advantages

  • Afraid of change ? Not anymore !
  • Any change in the code, effects known immediately.
  • “A test is not something you “do”, it is something you “write” and run once, twice, three times, etc.”

Best Practice: Tools like Nant can be used for automated scheduled builds. With every build, Nant will run the Nunit tests, and results will be produced in an XML file!

Test Driven Development – TDD

The concept of test driven can simply be put in the following two lines.

“The first step is to quickly add a test, basically just enough code to fail. Next you run your tests, often the complete test suite although for the sake of speed you may decide to run only a subset, to ensure that the new test does in fact fail. You then update your functional code to make it pass the new tests. The fourth step is to run your tests again. If they fail, you need to update your functional code and retest. Once the tests pass, the next step is to start over (you may first need to refactor any duplication out of your design as needed, turning TFD into TDD)”.

tdd_-_Copy.png

This is an iterative process which you continue till all your tests pass.

Some proven advantages of TDD:

  • Unit tests find problems early in the development cycle
  • An automated unit test suite watches over your code in two dimensions: time and space
  • Developers will be less afraid to change existing code
  • The development process becomes more flexible
  • Improves your project’s truck factor
  • The need for manual testing
  • That software development will become more predictable and repeatable
  • Shorter development cycle

Something of interest to project mangers reading this:

TDDchange_-_Copy.png

The green graph shows the TDD cycle, while the red one is the traditional development method of coding and then testing.

Caution

Before concluding the article, one small word of caution:

  • Having all the greens doesn't mean the software is ready to be delivered.
  • Unit testing DOES NOT replace traditional system testing.

Coming Soon

Once you start using TDD, you might come across certain challenges. You might need to implement proper design patterns and mocking to successfully implement unit testing and TDD. My next article will cover the same. Be patient, it will come soon.

History

  • 24th February, 2011: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)