NUnit: A Sample Application For Explanation

Ha! It has been a long time! It was hard to pull myself into this space amid professional turmoil.

So far, NUnit is a commonly used and excellent framework for debugging and running unit tests. It is widely used because it is open source and it easily mingled with Visual Studio 2010+. I am categorizing this article into the following six parts:

  1. Installation
  2. Ways to run unit tests
  3. Attributes to write NUnit tests
  4. Assertions
  5. A sample project to describe some attributes
  6. Limitations of NUnit

1. Installation

Unfortunately, the Visual Studio Team from Microsoft missed the NUnit reference by default. I was thinking, why did Microsoft not think about Unit/MSTest templates separately? When we create a MVC application we are prompted to choose an empty, internet, intranet, Web API and so on template. In a similar way, when selecting class libraries (Folks, I mean it, "class library", all the NUnit tests should be of a class library so that the output DLL is run for the result. Confusing? Don't stop, go ahead, you will understand this very shortly.) why can't we choose a test case template? Okay. Some things can never be changed from our end. If you want to use NUnit, install it either a) using the Nuget package for <a hreg=>NUnit</a> or using their <a href=> official website</a>. Follow these instructions in the link for installation and come back.

2. Ways to run unit tests

So far, until this moment, my teammates and the people around me are using three ways to run unit tests.

You should have your NUnit test project compiled and the DLL should be present in the bin directory (and we are all set to do this in Step 3).

  1. From your Visual Studio 2010 or above, click on the tools then select Windows -> Test Explorer. (Mine is vs2013). It lists all of your test methods.

  2. A Nunit.exe file found during your installation from the official website above. After installation check this area "C:\Program Files (x86)\NUnit 2.X.X\bin\nunit.exe".

  3. This is what we do in our organization, we have Resharper and we right-click on the test methods to either dubug or run our test files.

I prefer the second method since I will create a sample.

3. Some important attributes to write NUnit tests

I will list here some of the most commonly used attributes. As you know products around us update continuously and NUnit is not an exception.

  1. [TestFixture]: This attribute helps NUnit to identify a specific class as a NUnit Test Class.

  2. [SetUp]: If you have a common set of functions to execute before your test methods, use this attribute. It applies its magic with derived classes also.

  3. [TearDown]: This one and [SetUp] are antonyms. [SetUp] is called before the test method is executed and [TearDown] is executed after the test method's execution. We use this attribute for disposing of used objects and closing db connections in the method decorated with [TearDown].

  4. [Expected Exception]: Of Course, we do check for exceptions during test methods. If 1 is divided by 0 it must be tested for a DividedByZero Exception.

  5. [Ignore]: To avoid a test to run. Methods having this attribute will not run.

  6. [Explicit]: If we have N tests running in your test explorer and you want to omit one or more among them during bulk run, this will be helpful. Later on, you can click on this test and run it individually. We had test method connecting to Gmail servers to verify the sending of email. We had 2000 tests for our product with 5 regarding the sending of email. One day the Gmail server was down and the tests took a long time to complete. Guess what, next time we made it explicit to make other tests run first to make it run manually.

The detailed attributes can be found on the NUnit's official documentation. The preceding are the attributes we use in our everyday life of running tests.

4. Assertions

Assertions help us to judge the type of test output we get from our test methods. Remember, Unit Tests can only be run against a specific method or functionality/implementation. Assertions, in simple words, will help you to identify what type of results we obtain from these functions. It asserts your expected output with the actual output to make the test pass.

The commonly used assertions are the following:

  1. Assert.IsTrue( bool );  
  2. Assert.IsFalse( bool );  
  3. Assert.IsNull( bool );  
  4. Assert.IsNotNull( bool );  
  5. Assert.AreSame( objectobject )  
  6. Assert.AreEqual( objectobject );  
  7. Assert.AreEqual( intint );  
  8. Assert.AreEqual( floatfloatfloat );  
  9. Assert.AreEqual( doubledoubledouble );  
  10. Assert.Fail();  
5. A simple project to describe some attributes

Okay! This time enough of our stories, we need to open our Visual Studio. I am creating a very simple project to verify that the tests are working. Remember, in the real world, things are complex with strong SOLID principles implemented, design patterns are implemented in detail. We will not make things complex here. But, SOLID and Design Patterns are mandatory. If you, the reader, is a great fan of algorithms, I am so sorry. My brain has become a little rusty to think about time complexity when creating this. My sincere apologies. You will enjoy this though.

The following code allows users to enter a string to count the vowels in the string. 
  1. I have created a sample console application named NUnitBlog.

  2. I have created a class ClassForTest that has a method FindVowels that helps to find the vowels in the entered string.
    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.Linq;  
    4. using System.Text;  
    5. using System.Threading.Tasks;  
    7. namespace NUnitBlog  
    8. {  
    9.     public sealed class Program  
    10.     {  
    12.         static void Main(string[] args)  
    13.         {  
    15.             ClassForTest _class = new ClassForTest();  
    16.             _class.Operations();  
    17.         }  
    21.     }  
    23.     public class ClassForTest  
    24.     {  
    26.         public void Operations()  
    27.         {  
    28.             string InputString = "Krishnanand Sivaraj";  
    30.             int count = 0;  
    31.             count = FindVowels(InputString, count);  
    32.             Console.WriteLine(count);  
    33.             Console.ReadLine();  
    35.         }  
    37.         public int FindVowels(String InputString, int count)  
    38.         {  
    39.             char[] StringArray = InputString.ToCharArray();  
    40.             int input;  
    41.             if (StringArray.Length == 0)  
    42.             {  
    43.                 return 0;  
    44.             }  
    45.             for (input = 0; input < StringArray.Length; input++)  
    46.             {  
    47.                 if (StringArray[input] == 'a' || StringArray[input] == 'e' || StringArray[input] == 'i' ||  
    48.                     StringArray[input] == 'o' || StringArray[input] == 'u')  
    49.                 {  
    50.                     count++;  
    51.                 }  
    52.             }  
    53.             return count;  
    54.         }  
    55.     }  
    57. }  
  3. The preceding class helps us to get the vowels count in the specific string. We are accepting the input as a string and converting it to a string array. Later, In the FindVowels method, we are getting the total count of vowels. Here FindVowels is created since Unit tests can be run against a specific method.

  4. I will click on the solution in the Solution Explorer to add another new project of type class library. Let us follow a small naming convention and name it <projectnametotest>.Tests so that in the future we can identify which test project is used against that test class project.

  5. Add a reference to NUnit after installing it from Nuget or from a website.

  6. Reference it in your class library .cs file along with the project file.
    1. using NUnit.Framework;  
    2. using NUnitBlog;  
  7. The following test class describes the complete implementation.
    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.Linq;  
    4. using System.Text;  
    5. using System.Threading.Tasks;  
    6. using NUnit;  
    7. using NUnit.Framework;  
    8. using NUnitBlog;  
    10. namespace NUnitBlogPost.Tests  
    11. {  
    12.     [TestFixture]  
    13.     public sealed class NUnitBlogTest  
    14.     {  
    15.         private ClassForTest _program;  
    16.         [SetUp]  
    17.         public void SetUp()  
    18.         {  
    19.             _program = new ClassForTest();  
    20.         }  
    21.         [TestCase("Johne", 0, ExpectedResult = 2, TestName = "Check One")]  //Input to CheckVowels - stringarray="johne", count =0, testname=  Check One   
    22.         [TestCase(0, 0, ExpectedException = typeof(ArgumentException), TestName = "Check Three")] //Same syntax as above.  If input is an integer, throws exception  
    23.         public int CheckVowels(String StringArray, int count)  
    24.         {  
    25.             return _program.FindVowels(StringArray, count);  
    26.         }  
    28.         //Checks for null inputs  
    29.         [Test]  
    30.         public void NullTest()  
    31.         {  
    32.             int result = _program.FindVowels("",0);  
    33.             Assert.AreEqual(0,result);  
    34.         }  
    36.         //checks for non-voweled characters  
    38.         [Test]  
    39.         public void NonVowelStringTest()  
    40.         {  
    41.             int result = _program.FindVowels("dfghjkl", 0);  
    42.             Assert.AreEqual(0, result);  
    43.         }  
    44.     }  
    45. }  
    We can expand our test methods considering various scenarios.

    The test output will be like this if you run NUnit externally installed from its official website.


6. Limitations of NUnit

NUnit can only load assemblies as permitted under .NET's Code Access Security. Using the default settings, this means that you will be unable to load from any UNC path, including one that specifies the name of the local computer. Although you may use the .NET Framework configuration utility to allow loading of such applications, you must do this with care. Often, the simplest approach is to copy assemblies being tested to your local drive.