Understanding Unit and NUint Testing


What is Unit testing: A unit is a piece of code or usually method that invokes another piece of code and checks the correctness of some assumptions afterward? If the assumptions turn out to be wrong, the unit test has failed. A unit test is a method or function.

This definition is from Wikipedia

UnitTst1.gif

Property of Unit test: A unit test has the following properties

  1. It should be automated and repeatable.
  2. It should be easy to implement.
  3. Once written, it should remain for future use.
  4. Anyone should be able to run it.
  5. It should run quickly.

Many of us get confused with the act of testing of software with the concept of a unit test. To start off, ask yourself the following questions about the tests you've written up to now:

  • Can I run and get results from a unit test I wrote two weeks or months or years ago?
  • Can any member of my team run and get the results from unit tests I wrote two months ago?
  • Can I run all the unit tests I've written in no more than a few minutes?
  • Can I run all the unit tests I've written at the push of a button?
  • Can I write a basic unit test in no more than a few minutes?

If you've answered "no" to any of these questions, there's a high probability that what you're implementing isn't a unit test. It's definitely some kind of test, and it's as important as a unit test, but it has drawbacks compared to tests that would let you answer "yes" to all of those questions.

A simple unit test example: It's possible to write an automated unit test without using a test framework. In this section, I'll show what writing such a test without a framework can look like, so that when I later in article demonstrate, you can contrast this with using a framework.

Assume we have a SimpleParser class that we'd like to test. It has a method named ParseAndSum that takes in a string of 0 or more comma-separated numbers. If there are no numbers, it returns 0. If there's a single number, it returns that number as an int. If there are multiple numbers, it adds them all up and returns the sum (although, right now, the code can only handle 0 or 1 number).

public class SimpleParser
    {

        public int ParseAndSum(string numbers)
        {
            if (numbers.Length == 0)
            {
                return 0;
            }
            if (!numbers.Contains(","))
            {
                return int.Parse(numbers);
            }
            else
            {
                throw new InvalidOperationException(
                "I can only handle 0 or 1 numbers for now!");
            }

        }
    }

We can create a simple console application project that has a reference to the assembly containing this class, and we can write a SimpleParserTests method as shown in below code. The test method invokes the production class (the class to be tested) and then checks the returned value. If it's not what's expected, it writes to the console. It also catches any exception and writes it to the console

public class SimpleParserTests
    {
        public static void TestReturnsZeroWhenEmptyString()
        {
            try
            {
                SimpleParser p = new SimpleParser();
                int result = p.ParseAndSum(string.Empty);
                if (result != 0)
                {
                }
                Console.WriteLine(
            @"***SimpleParserTests.TestReturnsZeroWhenEmptyString:
-------
Parse and sum should have returned 0 on an empty string"
);
            }

            catch (Exception e)
            {
                Console.WriteLine(e);
            }

Next, we can invoke the tests we've written by using a simple Main method run inside a console application in this project, as seen in code below. The Main method is used here as a simple test runner, which invokes the tests one by one, letting them write out to the console. Because it's an executable, this can be run without human intervention (assuming the tests don't pop up any interactive user dialogs).

public static void Main(string[] args)
    {
        try
        {
                SimpleParserTests.TestReturnsZeroWhenEmptyString();
        }
        catch (Exception e)
        {
                Console.WriteLine(e);
        }
    }

It's the test method's responsibility to catch any exceptions that occur and write them to the console, so that they don't interfere with the running of subsequent methods. We can then add more method calls into the Main method as we add more and more tests to the project. Each test is responsible for writing the problem output (if there's a problem) to the console screen.

Obviously, this is an ad hoc way of writing such a test. If you were writing multiple tests like this, you might want to have a generic ShowProblem method that all tests could use, which would format the errors consistently. You could also add special helper methods that would help check on various things like null objects, empty strings, and so on, so that you don't need to write the same long lines of code in many tests.

The below code shows what this test would look like with a slightly more generic ShowProblem method.

Using a more generic implementation of the ShowProblem method.

public class TestUtil
    {
        public static void ShowProblem(string test, string message)
        {
            string msg = string.Format(@"
---{0}---
{1}
--------------------
"
, test, message);
            Console.WriteLine(msg);
        }
    }
public static void TestReturnsZeroWhenEmptyString()
    {
        //use .NET's reflection API to get the current method's name it's possible to hard code this,but it's a useful technique to know
        string testName = MethodBase.GetCurrentMethod().Name;  
        try
        {
            SimpleParser p = new SimpleParser();
            int result = p.ParseAndSum(string.Empty);
            if(result!=0)
            {
                //Calling the helper method
                TestUtil.ShowProblem(testName,
                "Parse and sum should have returned 0 on an empty string");
             }
        }
        catch (Exception e)
        {
            TestUtil.ShowProblem(testName, e.ToString());
        }
    }

Unit-testing frameworks can help make helper methods more generic like this, so tests are written more easily.

What is NUnit: A new way to writing real-world unit tests with a framework called NUnit-a .NET unit-testing framework. It's my favorite framework in .NET for unit testing because it's easy to use, easy to remember, and has lots of great features.

So before we start working with NUnit, we need to look at what a unit-testing framework is, and at what it enables us to do that we couldn't and wouldn't have done without it.

The points to be remembered about NUnit are listed below:

  1. NUnit is not an automated GUI testing tool.

  2. It is not a scripting language, all test are written in .NET supported language, e.g., C#, VC, VB.NET, J#, etc.

Frameworks for unit testing: Consider the advantages an integrated development environment (IDE) gives you as a developer. Unit-testing frameworks offer similar advantages for testing. When using a modern IDE like Visual Studio .NET or Eclipse for Java, you do all your coding tasks within that Environment, in a structured manner. You write the code, you compile it, you build any resources (like graphics and text) into it, and you create the final binary-all that building and compiling with no more than a couple of keystrokes. Doing things completely manually would be error-prone and time-consuming, and people would defer doing that as much as possible. These problems are alleviated by tooling. In the same way, unit-testing frameworks help developers write tests more quickly with a set of known APIs, execute those tests automatically, and review the results of those Tests easily.
So now we are ready to start using NUnit framework for doing unit testing. I have compiled this exercise in below steps.

Step 1: Download NUnit

1. Download NUnit from http://www.nunit.org/index.php?p=download
Download Window version i.e.
win NUnit-2.5.10.11092.msi

Step 2: Installing NUnit

To install NUnit, runs the setup program you downloaded. The installer Will place a shortcut to the GUI part of the NUnit runner on your desktop, but the main program files should reside in a directory named something like c:\Program Files\NUnit-Net-2.5 .10.

Step 3: Loading up the solution

The NUnit GUI is divided into three main parts: the tree listing the tests on the left, messages and errors at the top right and stack trace information at the bottom right.

UnitTst2.gif

Step 4: Create a Window Console Project in Visual Studio

In program.cs write below code. We here in below code are adding and subtracting two integers.

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Enter two numbers\n");
            int iNumber1;
            int iNumber2;
            iNumber1 = int.Parse(Console.ReadLine());
            iNumber2 = int.Parse(Console.ReadLine());
            HelperClass helper = new HelperClass();
            int x = helper.Add(iNumber1, iNumber2);
            Console.WriteLine("\nThe sum of " + iNumber1 + " and " + iNumber2 + " is " + x);
            Console.ReadKey();
            int y = helper.Subtract(iNumber1, iNumber2);
            Console.WriteLine("\nThe difference between " + iNumber1 + " and" + iNumber2 + "  is " + y);
            Console.ReadKey();
        }
    }
    public class HelperClass
    {
        public HelperClass() { }
        public int Add(int a, int b)
        {
            int x = a + b;
            return x;
        }
        public int Subtract(int a, int b)
        {
            int x = a - b;
            return x;
        }
    }

UnitTst3.gif

Step 5: Creating Test Project

  • Now to the solution of the project, add a new class library project and name it followed by ".Test" (it is the naming convention used for unit testing). Import the downloaded DLL files into the project and follow the steps given below.

  • Adding NUnit reference in your Visual Studio 2008 IDE.

    UnitTst4.gif
     

  • In the newly added project, add a class and name it as TestClass.cs.

  • Add nunit framework reference in class.

    using NUnit.Framework;
     

  • Add reference to your main code project.

    UnitTst5.gif

    using NUnitProjectOne;
     

  • In the class file, write the following code:

    namespace Nunit.Test
    {
        [TestFixture]
        public class TestClass
        {
            [TestCase]
            public void AddTest()
            {
                HelperClass helper = new HelperClass();
                int result = helper.Add(20, 10);
                Assert.AreEqual(30, result);
            }

            [TestCase]
            public void SubtractTest()
            {
                  //Arrange
                HelperClass helper = new HelperClass();
                  //Act
                int result = helper.Subtract(20, 10);
                //Assert
               
    Assert.AreEqual(10, result);
            }
        }
    }

Unit test usually comprises three main actions:

  • Arrange objects, creating and setting them up as necessary.

  • Act on an object.

  • Assert that something is as expected.

Step 7: How to run the NUnit GUI runner from within Visual Studio C# Express 2008

We can run NUnit from the Menu option it installed under [Start/Programs/NUnit] but it is more convenient to do so from Visual Studio Express itself.
Visual Studio C# Express allows you to define outside "Tools" which can be run from the menu. This is exactly what we would like to do with the NUnit GUI Runner. The GUI Runner is a tool which loads our program and executes all the unit tests it finds and reports the results in a separate window.

Click on "Tools > External Tools…" to add NUnit's GUI Runner.

UnitTst6.gif

The following definition allows us to run the tests in our current project:

UnitTst7.gif

Configuring Nuint to enable it to open within Visual Studio

To run the unit test, simply click "NUnit" from the Tools Menu.

UnitTst8.gif

UnitTst9.gif

Select NUint to run .

Nunit test result

Now lets change result value in TestClass and then see how NUnit tests it.

[TestFixture]
    public class TestClass
    {
        [TestCase]
        public void AddTest()
        {
            HelperClass helper = new HelperClass();
            int result = helper.Add(20, 10);
            Assert.AreEqual(50, result);
        }

        [TestCase]
        public void SubtractTest()
        {
            HelperClass helper = new HelperClass();
            int result = helper.Subtract(20, 10);
            Assert.AreEqual(10, result);
        }
    }

Built this and run the NUnit. This time it show error for Add method.

UnitTst10.gif

Step 7: Understanding Terms

  1. [TestFixture]

    The [TestFixture] attribute denotes a class that holds automated NUnit tests. (If you replace the word "Fixture" with "Class", it makes much more sense.)

  2. [TestCase]

    The [Test] attribute can be put on a method to denote it as an automated test to be invoked. Put this attribute on your new test method.

  3. Assert

    The Assert class has static methods and is located in the NUnit.Framework namespace. It's the bridge between your code and the NUnit framework, and its purpose is to declare that a specific assumption is Supposed to exist. If the arguments that are passed into the Assert class turn out to be different than what we're asserting, NUnit will realize the test has failed and will alert us. We can optionally tell the Assert class what message to alert us with if the assertion fails. The Assert class has many methods, with the main one being Assert.IsTrue (some Boolean expression), which verifies a Boolean Condition. But there are many other methods. This one verifies that an expected object or value is the same as the actual one:

    Assert.AreEqual(expectedObject, actualObject, message);
    Here's an example:
    Assert.AreEqual(2, 1+1, "Math is broken");

  4. [Setup]:

    Is generally used for any initialization purpose. Any codes that must be initialized or set prior to executing a test are put in functions marked with this attribute. As a consequence, it avoids the problem of code repetition in each test.

  5. [Ignore]:

    This is the attribute which is used for the code that needs to be bypassed.
     

  6. [ExceptionExpected]

    This attribute is used to test methods that need to throw exception in some cases. The cases may be FileNotFoundException and others.

  7. [TearDown]:

    This attribute denotes a method to be executed once after each test in your class has executed.

Conclusion:

  1. Its common practice to have one test class per tested class, one test project per tested project, and at least one test method per tested method.

  2. Use the [SetUp] and [TearDown] attributes to reuse code in your tests, such as code for creating and initializing objects all your tests use.

Hope you enjoyed this ride about unit testing and NUnit. Cheers

Up Next
    Ebook Download
    View all
    Learn
    View all