This article will describe all aspects of NUnit starting from Test Driven Development (TDD) to converting it to data driven test. I will also show you how easy it is to compute the code coverage in Visual Studio 2015.
I have briefly mentioned NUnit test with Visual Studio in one of my previous articles (Code Quality Tools in Visual Studio 2015).
NUnit Overview
Unit Testing in simple words is a testing process in which a unit of code is tested. Unit Testing is typically an automated functionality testing.
Visual Studio provides support for unit testing via the MS Test framework as well as third party frameworks like NUnit. Unit Tests are written by the same developers who are writing that unit of code.
NUnit is a unit testing framework which can be used for .Net languages. This is an Open Source Software. It is similar to Junit which is used for Java.
NUnit can be incorporated in Visual Studio by installing NuGet packages of NUnit. I am now going to walk you through the process of installation and use of Nunit framework.
Unit tests
Let us start from scratch by creating an empty solution in VS 2015.
I have added a class library to the solution which has some methods for which we will write NUnit tests.
public class ClassForNUnit
{
public int Sum(int i, int j)
{
return i + j;
}
public string Concat(string str1, string str2)
{
return "Hello " + str1 + " " + str2;
}
public int Sum(int[] i)
{
int res = 0;
for (int a = 0; a < i.Length; a++)
{
res += i[a];
}
return res;
}
}
As usual, if we select a method and right click on it we will get the option of Create Unit Tests.
Observe the default support to the MS Test framework in the screenshot below, which we are not going to use in this walkthrough.
If you click on the get additional extensions link, it will take us to MSDN document for adding reference to third party frameworks. We can cancel this window and find out how to reference to NUnit using NuGet packages.
Installing NUnit
Add a project of type Unit Test Project to the solution.
Change the name of .cs file to an appropriate name and remove the attributes for the class along with the existing method (we do not need the attributes of MS Testing Framework).
Let us select Manage NuGet Packages for the unit testing project, go to browser and enter nunit in the search window.
Select NUnit and NUnitTestAdapter as the packages to install one after the other. Packages.config file will automatically get added to the project.
Change the code for the test method as follows. Do not forget to add reference to the class library project.
[TestFixture]
public class NUnitDemo
{
[Test]
public void TestMethodSum()
{
}
}
Look at the attributes for the class and the test method.
The complete code for the method looks as follows:
[Test]
public void TestMethodSum()
{
int actual, expected = 30;
ClassLibNUnit.ClassForNUnit target = new ClassLibNUnit.ClassForNUnit();
actual = target.Sum(12, 18);
NUnit.Core.NUnitFramework.Assert.AreEqual(expected, actual);
}
Build the solution and you will observe that the method is not shown in Test Explorer. Strange as it sounds, we need to select the version for NUnit as 2.6.4 rather than the latest which is 3.6.0.
Change the version and now you can see the test appearing in Test Explorer. Build the solution and execute the test from Test Explorer. It shoud pass without any issues.
Test Driven Development (TDD)
Let us find out about Test Driven Development (TDD).
I have discussed TDD technique in one of the articles named “Best Practices of Agile Development – Using Visual Studio 2015 and Team Foundation Server 2015” which was published in Jan 2017 DNC magazine issue. You can also find it at https://www.dotnetcurry.com/visualstudio/1338/agile-development-best-practices-using-visual-studio.
In simple words, TDD is a technique where we first design a test which fails, as we have not written any code to be tested yet. Then the code to be tested is written and test is executed again. It may fail again.
The process involves refining the code and running the test again and again, until the test passes.
Let us add another test method as follows
[TestFixture]
public class NUnitDemo
{
[Test]
public void TestMethodSubt()
{
NUnit.Framework.Assert.Fail();
}
}
Right click on the test and select run and you will observe that the test fails. This is because we have not added any code which can be tested.
Let us go back to the class library and add a method for the subtraction of two numbers.
public int Subt(int i, int j)
{
return i - j;
}
Now we will have to change the test method properly and execute it again.
[Test]
public void TestMethodSubt()
{
int actual, expected = 10;
ClassLibNUnit.ClassForNUnit target = new ClassLibNUnit.ClassForNUnit();
actual = target.Subt(10,0);
NUnit.Core.NUnitFramework.Assert.AreEqual(expected, actual);
}
This time the test will pass.
Data Driven NUnit Test
Every time we run any of the above tests, it will use the same values for parameters which may not be ideal. We need to provide different values when the test gets executed. In order to achieve this, let us find out how to send values via variables and not via constants.
This technique is called Data Driven Testing.
Change the attribute as follows and build the code, you will observe the change in the test.
[Test, TestCase(10, 20)]
We can see the values of the parameters.
Just changing the parameters is not enough as we also have to provide them to the method under test. We need to do this by providing a list of parameters for the test method and also using them when calling the method to test.
I will also add the expected value as parameter and the code looks as follows.
[Test, TestCase(10, 20, 30)]
public void TestMethodSum(int num1,int num2, int res)
{
int actual, expected = res;
ClassLibNUnit.ClassForNUnit target = new ClassLibNUnit.ClassForNUnit();
actual = target.Sum(num1, num2);
NUnit.Core.NUnitFramework.Assert.AreEqual(expected, actual);
}
We can even do multiple iterations as follows which will result in more number of tests appearing in Test Explorer (this behavior is similar to IntelliTest feature which is available in Visual Studio 2015)
[Test, TestCase(10, 20, 30)]
[TestCase(1, 2, 3)]
[TestCase(12, 20, 22)]
We can run all the tests at once and find out the ones that fail.
Sending Arrays as Parameters to the Test
Let us find how an array can be sent as parameters to the test.
I have declared a multi-dimensional array whose last element is the expected value for sum. I also added another method which tests the overloaded method for sum.
static int[][] Numbers = { new int[] { 5, 4, 2, 11 }, new int[] { 6, 4, 10 } };
[Test, TestCaseSource("Numbers")]
public void TestSumConstant(int[] num)
{
int actual, expected = num[num.Length-1];
ClassLibNUnit.ClassForNUnit target = new ClassLibNUnit.ClassForNUnit();
List<int> param = new List<int>();
for (int i = 0; i < num.Length-1; i++)
{
param.Add(num[i]);
}
actual = target.Sum(param.ToArray());
NUnit.Core.NUnitFramework.Assert.AreEqual(expected, actual);
}
Observe that the dimension of array is dynamic and in order to use it, I have used List and then converted it to an int array (a workaround to allow dynamic dimension for array in C#).
Also note how the expected value is taken as the last element in the array.
The method is shown as
As against to the previous option, the parameter values are not displayed but the array is shown as a parameter.
The problem in both of the above situations is we are providing the values before run and they cannot be changed on the fly. In order to provide values on the fly we can be create a .csv file with data.
Providing data to the Test using CSV
Let us create a .csv file with some data in it. I have added the following data to the file.
This data has varying lengths of array and the last element is the expected value. We need to provide an attribute as well and add a class which has IEnumerable interface.
IEnumerable interface contains a single method GetEnumerator. The attribute looks as follows.
[Test, TestCaseSource(typeof(GetTestDt), "GetTestData")]
I have further written a class with the name as GetTestDt which has IEnumerable with name GetTestData
public class GetTestDt
{
string CSVFileName = @" \data.csv";
public int input { get; set; }
public int output { get; set; }
public IEnumerable GetTestData
{
get
{
using (var inputStream = new FileStream(CSVFileName, FileMode.Open, FileAccess.Read))
{
using (var streamReader = new StreamReader(inputStream))
{
string inputLine;
while ((inputLine = streamReader.ReadLine()) != null)
{
var data = inputLine.Split(',');
List param = new List();
for (int i = 0; i < data.Length ; i++)
{
param.Add(Convert.ToInt32(data[i]));
}
yield return new[] { param.ToArray() };
}
}
}
}
}
}
The test method looks as follows:
[Test, TestCaseSource(typeof(GetTestDt), "GetTestData")]
public void TestSumCsvFile(int[] num)
{
int actual, expected = num[num.Length-1];
ClassLibNUnit.ClassForNUnit target = new ClassLibNUnit.ClassForNUnit();
List<int> param = new List<int>();
for (int i = 0; i < num.Length - 1; i++)
{
param.Add(num[i]);
}
actual = target.Sum(param.ToArray());
NUnit.Core.NUnitFramework.Assert.AreEqual(expected, actual);
}
I have yet again used a List and converted it to array in order to keep array length as flexible. Now observe the TestSumCsvFile(int[] num) method with integer array as parameter and it executes for as many number of records in the csv file.
We can change the data on the fly in the data file and every time the test method will be executed with different set of data.
Code Coverage for Test Methods
Code Coverage is a process of finding out if the code you have written is being tested properly or not.
With Visual Studio, we get blue and red colors which indicate portions of code that was reached, and the ones which was not reached while running the test.
Capturing Code Coverage data is very straight forward as we just need to select the method(s), right click and select Analyze Code Coverage for Selected Tests.
If you want the data for all the tests, click on down arrow for Run and select Analyze Code Coverage for All Tests. The Code Coverage window will be added automatically once the test methods are executed. See the screenshot below.
The data is shown for % of Blocks as not covered and covered. You can select Add and Remove Columns and you get following options.
You can add or remove columns as per your need and find colored statements.
public int Sum(int i, int j)
{
return i + j;
}
public int Subt(int i, int j)
{
return i - j;
}
public string Concat(string str1, string str2)
{
return "Hello " + str1 + " " + str2;
}
public int Sum(int[] i)
{
int res = 0;
for (int a = 0; a < i.Length; a++)
{
res += i[a];
}
return res;
}
If you have not written any test methods for a piece of code, you will see red color for them (eg: Concat). Add test methods for the remaining functionality and you will get 100% code coverage.
Conclusion
In this article, I have discussed NUnit testing from scratch and how to incorporate it for Visual Studio 2015.
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Gouri is a Trainer and Consultant on Azure DevOps and Azure Development. She has an experience of three decades in software training and consulting. She is a graduate from Pune University and PGDCA from Pune University. Gouri is a Microsoft Most Valuable Professional (MVP) - Developer Technologies (Azure DevOps), Microsoft Certified Trainer (MCT) and a Microsoft Certified Azure DevOps Engineer Expert. She has conducted over 150 corporate trainings on various Microsoft technologies. She is a speaker with Pune User Group and has conducted sessions on Azure DevOps, SQL Server Business Intelligence and Mobile Application Development. Gouri has written more than 75 articles on Azure DevOps, TFS, SQL Server Business Intelligence and SQL Azure which are published on
www.sqlservercurry.com and
www.dotnetcurry.com. You can connect with her on
LinkedIn.