Unit Test In .NET Core Application Using NUnit

Introduction
 
There are three different test frameworks that are supported by ASP.NET Core for unit testing - MSTest, xUnit, and NUnit. These allow us to test our code in a consistent way. In this article, I will explain about the unit test using NUnit.
 
NUnit is an open source unit test framework for all .NET languages. It is initially ported from JUnit. The current released version of NUnit is 3 which has been completely rewritten with many new features.
 
To demonstrate the example of the unit test, I have created an MVC project, solution, and a unit test project by using CLI (Command Line Interface). To create an MVC and Test project, I am following the below steps.
 
Step 1

Create a solution file using the following command. This command creates an empty solution.
  1. >dotnet new sln -n MVCUnittest  
Step 2

Create an MVC project using the following command.
  1. >dotnet new MVC  
Step 3

Adding this project to solution, just use the following command.
  1. >dotnet sln add Unittest\Unittest.csproj  
Step 4 - Create NUnit test project

There is no direct template available for NUnit by default. If we want a template for NUnit, we need to install that by using the following command.
  1. >dotnet new -i NUnit3.DotNetNew.Template  
As an alternate way, we can create class library project and add reference to NUnit. The current version of NUnit is 3. It can be installed either from NuGet packages or from .NET Core CLI tool. The following command is used to install NUnit using NuGet packages (Package Manager).
  1. PM>Install-Package NUnit -Version 3.9.0  
Using the following .NET CLI command, we can install NUnit.
  1. >dotnet add package NUnit --version 3.9.0  
If the template for NUnit has been installed, we can create NUnit project using the following command.
  1. >dotnet new nunit  
This command creates NUnit Test Project and generates a template that configures Test runner into .csproj file.
  1. <ItemGroup>  
  2.   <PackageReference Include="nunit" Version="3.9.0" />  
  3.   <PackageReference Include="NUnit3TestAdapter" Version="3.9.0" />  
  4.   <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />  
  5. </ItemGroup>  
The generated code also has dummy unit test files. It looks as following.
  1. using NUnit.Framework;  
  2.   
  3. namespace Tests  
  4. {  
  5.     public class Tests  
  6.     {  
  7.         [SetUp]  
  8.         public void Setup()  
  9.         {  
  10.         }  
  11.   
  12.         [Test]  
  13.         public void Test1()  
  14.         {  
  15.             Assert.Pass();  
  16.         }  
  17.     }  
  18. }  
NUnit has very similar attribute terminology as MSTest. The TextFixture is same as TestClass attribute in MSTest; it denotes a class that contains the unit test. The Test attribute is same as TestMethod attribute in MSTest; it denotes that a method is a test method. The SetUp attribute is used to identify a method which is called immediately before each test.
 
Step 5

Adding test project to solution.
  1. >dotnet sln add TestProject\Testproject.csproj  
To demonstrate the concept, I have created a method within HomeController class (GetEmployeeName). This method accepts empId as parameter and based on that, it will return teh name of the employee or "Not Found" hard code string.

HomeController
  1. public string GetEmployeeName(int empId)  
  2. {  
  3.     string name;  
  4.     if (empId == 1)  
  5.     {  
  6.         name = "Jignesh";  
  7.     }  
  8.     else if (empId == 2)  
  9.     {  
  10.         name = "Rakesh";  
  11.     }  
  12.     else  
  13.     {  
  14.         name = "Not Found";  
  15.     }  
  16.     return name;  
  17. }  
In the following test method, I have pass hardcoded value and checked the result using Assert class.

UnitTest1.cs
  1. using NUnit.Framework;  
  2. using UnitTest.Controllers;  
  3.   
  4. namespace Tests  
  5. {  
  6.     public class Tests  
  7.     {  
  8.         [SetUp]  
  9.         public void Setup()  
  10.         {  
  11.         }  
  12.   
  13.         [Test]  
  14.         public void Test1()  
  15.         {  
  16.             HomeController home = new HomeController();  
  17.             string result = home.GetEmployeeName(1);  
  18.             Assert.AreEqual("Jignesh", result);  
  19.         }  
  20.     }  
  21. }  
The final step is to run the Unit test. Using the following command, we can run our all test cases.
  1. >dotnet test  
  2. >dotnet test --filter "FullyQualifiedName=TestProject.UnitTest1.Test1"  
Result
 
 
 
We also run all test cases or individual tests within Visual Studio using Test Explore.
 
 
 
In the preceding example, my test result (actual) has matched with the expected result. In the following example, my actual result does not match with the expected result.
  1. [Test]  
  2. public void Test2()  
  3. {  
  4.     HomeController home = new HomeController();  
  5.     string result = home.GetEmployeeName(1);  
  6.     Assert.AreEqual("Rakesh", result);  
  7. }  
Result

 

To unit test the every block of code, we require more test data. We can add more test methods using Test attribute, but it is very tedious job.

NUnit also supports other attributes which enable us to write a suite for similar test. A TestCases attribute can be applied to the test that can take the test data directly using the provided data or Excel spreadsheet. Instead of creating a new test, we can use this attribute to create a single data driven test.
 
The TestCase attribute may appear one or more times on a test method that contains the test data as a parameter. The method may optionally be marked with Test attribute as well.
  1. using NUnit.Framework;  
  2. using UnitTest.Controllers;  
  3.   
  4. namespace Tests  
  5. {  
  6.     public class Tests  
  7.     {  
  8.         [TestCase(1, "Jignesh")]  
  9.         [TestCase(2, "Rakesh")]  
  10.         [TestCase(3, "Not Found")]  
  11.         public void Test3(int empId, string name)  
  12.         {  
  13.             HomeController home = new HomeController();  
  14.             string result = home.GetEmployeeName(empId);  
  15.             Assert.AreEqual(name, result);  
  16.         }  
  17.     }  
  18. }  
Unit test with ILogger

.NET Core supports built-in dependency injection. So, whatever the services we want to use during the execution of the code, those are injected as dependency. One of the best examples is ILogger Service. Using the following code, we can configure ILogger service in our ASP.NET Core project.
 
Configure ILogger in Program.cs
  1. using Microsoft.AspNetCore;  
  2. using Microsoft.AspNetCore.Hosting;  
  3. using Microsoft.Extensions.Logging;  
  4.   
  5. namespace Unittest  
  6. {  
  7.     public class Program  
  8.     {  
  9.         public static void Main(string[] args)  
  10.         {  
  11.             BuildWebHost(args).Run();  
  12.         }  
  13.   
  14.         public static IWebHost BuildWebHost(string[] args) =>  
  15.             WebHost.CreateDefaultBuilder(args)  
  16.                 .ConfigureLogging((hostingContext, logging) =>  
  17.                 {  
  18.                     logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));  
  19.                     logging.AddConsole();  
  20.                     logging.AddDebug();  
  21.                 })  
  22.                 .UseStartup<Startup>()  
  23.                 .Build();  
  24.     }  
  25. }  
TestController
  1. using Microsoft.AspNetCore.Mvc;  
  2. using Microsoft.Extensions.Logging;  
  3.   
  4. namespace Unittest.Controllers  
  5. {  
  6.     public class TestController : Controller  
  7.     {  
  8.         private readonly ILogger _logger;  
  9.         public TestController(ILogger<TestController> logger)  
  10.         {  
  11.             _logger = logger;  
  12.         }  
  13.           
  14.         public string GetMessage()  
  15.         {  
  16.            _logger.LogDebug("Test Method Called!!!");  
  17.             return "Hi! Reader";  
  18.         }  
  19.     }  
  20. }  
Unit Test Method

To unit test the controller having dependency on ILogger service, we have to pass ILogger object or null value to constructor. To create these types of dependencies, we can create an object of service provider and with the help of the service provider, we can create the object of such services.

In the following code, I have created a service provider object and created an ILogger object.
  1. [Test]  
  2. public void Test4()  
  3. {  
  4.     var serviceProvider = new ServiceCollection()  
  5.         .AddLogging()  
  6.         .BuildServiceProvider();  
  7.   
  8.     var factory = serviceProvider.GetService<ILoggerFactory>();  
  9.   
  10.     var logger = factory.CreateLogger<TestController>();  
  11.     TestController home = new TestController(logger);  
  12.     string result = home.GetMessage();  
  13.     Assert.AreEqual("Hi! Reader", result);  
  14. }  
Summary

Unit test is a code that helps us in verifying the expected behavior of the other code in isolation. Here, “In isolation" means there is no dependency between the tests. This is a better idea to test the application code, before it goes for quality assurance (QA). All Unit test frameworks - MSTest, XUnit, and NUnit - offer a similar end goal and help us to write unit tests that are simpler, easier, and faster. It is possible to use NUnit with .NET Core but some tasks are needed to be done manually because there is no template available with .NET Core.