RESTful Day #7: Unit Testing and Integration Testing in WebAPI using NUnit and Moq framework: Part 1

Table of Contents

  • Introduction
  • Roadmap
  • Unit Tests
  • NUnit
  • Moq Framework
  • Setup Solution
  • Testing Business Services
    • Step 1: Test Project
    • Step 2: Install NUnit package
    • Step 3: Install Moq framework
    • Step 4: Install Entity Framework
    • Step 5: Install AutoMapper
    • Step 6: References
    • TestHelper
    • ProductService Tests
      • Tests Setup
        • Declare variables
        • Write Test Fixture Setup
        • Write Test Fixture Tear Down
        • Write Test Setup
        • Write Test Tear down
        • Mocking Repository
        • Initialize UnitOfWork and Service
          1. GetAllProductsTest ()
          2. GetAllProductsTestForNull ()
          3. GetProductByRightIdTest ()
          4. GetProductByWrongIdTest ()
          5. AddNewProductTest ()
          6. UpdateProductTest ()
          7. DeleteProductTest ()

    • TokenService Tests
      • Tests Setup
        • Declare variables
        • Write Test Fixture Setup
        • Write Test Fixture Tear Down
        • Write Test Setup
        • Write Test Tear down
        • Mocking Repository
          1. GenerateTokenByUseridTest ()
          2. ValidateTokenWithRightAuthToken ()
          3. ValidateTokenWithWrongAuthToken ()
      • UserService Tests
      • WebAPI Tests
      • Conclusion
Introduction

We have been learning a lot in Web API. We covered almost all the techniques required to build a robust and a full stack REST service using asp.net Web API, right from creating a service to making it a secure and ready to use boilerplate with enterprise level applications. In this article we’ll learn on how to focus on test driven development and write unit tests for our service endpoints and business logic. I’ll use NUnit and Moq framework to write test cases for business logic layer and controller methods. I’ll cover less theory and focus more on practical implementations on how to use these frameworks to write unit tests. I have segregated the article into two parts. First part focuses on testing business logic and class libraries created as BusinessServices in our code base. Second part will focus on testing a Web API. The purpose of segregation is simple; the scope of this article is very large and may turn up into a very large post which would be not easy to read in a go.

Roadmap


The following is the roadmap I have setup to learn Web API step by step,

roadmap

I’ll purposely use Visual Studio 2010 and .net Framework 4.0 because there are few implementations that are very hard to find in .Net Framework 4.0, but I’ll make it easy by showing how we can do it.

Unit Tests

“Unit tests allow you to make big changes to code quickly. You know it works now because you’ve run the tests, when you make the changes you need to make, you need to get the tests working again. This saves hours.” I got this from a post at stack overflow, and I completely agree to this statement.

test

A good unit test helps a developer to understand his code and most importantly the business logic. Unit tests help to understand all the aspects of business logic, right from the desired input and output to the conditions where the code can fail. A code having a well written unit tests have very less chances to fail provided the unit tests cover all the test cases required to execute.

NUnit

There are various frameworks available for Unit tests. NUnit is the one that I prefer. NUnit gels well with .Net and provide flexibility to write unit tests without hassle. It has meaningful and self-explanatory properties and class names that help developer to write the tests in an easy way. NUnit provides an easy to use interactive GUI where you can run the tests and get the details .It shows the number of tests passed or fail in a beautiful fashion and also gives the stack trace in case any test fails, thereby enabling you to perform the first level of debugging at the GUI itself. I suggest downloading and installing NUnit on your machine for running the tests. We’ll use NUnit GUI after we write all the tests. I normally use inbuilt GUI of NUnit provided by Re-sharper integrated in my Visual Studio. Since Re-sharper is a paid library only few developers may have it integrated, so I suggest you to use NUnit GUI to run the tests. Since we are using Visual Studio 2010, we need to use the older version of NUnit i.e. 2.6.4. You can download and run the .msi and install on your machine following this URL.

nunit

Once you finish installation, you’llsee NUnit installed in your installed items on your machine as shown in below image,

nunit

Moq Framework

Moq is a simple and straight forward library to mock the objects in C#. We can mock data, repositories classes and instances with the help of mock library. So when we write unit tests, we do not execute them on the actual class instances, instead perform in-memory unit testing by making proxy of class objects. Like NUnit, Moq library classes are also easy to use and understand. Almost all of its methods, classes and interfaces names are self-explanatory.

The following is the list taken from Wikipedia on why to use mock objects,
  • The object supplies non-deterministic results (e.g., the current time or the current temperature);
  • Has states that are not easy to create or reproduce (e.g., a network error);
  • Is slow (e.g., a complete database, which would have to be initialized before the test);
  • Does not yet exist or may change behavior;
  • Would have to include information and methods exclusively for testing purposes (and not for its actual task).

So whatever test we write, we actually execute that on test data and proxy objects i.e. not the instances of real classes. We’ll use Moq to mock data and repositories so that we do not hit database again and again for executing unit tests. You can read more about Moq in this article.

Setup Solution

I’ll use this article to explain how to write unit tests for business logic i.e. covering our business logic layer and for WebAPI controllers. The scope of Unit tests should not be only limited to business logic or endpoints but should spread over all publically exposed logics like filters and handlers as well. Well written unit tests should cover almost all the code. One can track the code coverage through some of the tools available online. We’ll not test filters and common classes but will focus on controllers and business logic layer and get an idea of how to proceed with unit tests. I’ll use the same source code that we used till Day# 6 of the series and will proceed with the latest code base that we got out of last article of the series. Code base is available for download with this post. When you take the code base from my last article and open it in visual studio, you’ll see the project structure something like as shown in below image,

setup

IUnitOfWork is the new interface that I have added just to facilitate interface driven development. It helps in mocking objects and improved structure and readability. Just open the visual studio and add a new interface named IUnitOfWork under UnitOfWork folder in DataModel project and define the properties used in UnitOfWork class as shown below,

code

Now, go to UnitOfWork class and inherit that class using this interface, so UnitOfWork class becomes something like this,

  1. #region Using Namespaces...  
  2.   
  3. using System;  
  4. using System.Collections.Generic;  
  5. using System.Data.Entity;  
  6. using System.Diagnostics;  
  7. using System.Data.Entity.Validation;  
  8. using DataModel.GenericRepository;  
  9.  
  10. #endregion  
  11.   
  12. namespace DataModel.UnitOfWork  
  13. {  
  14.     ///<summary>  
  15.     /// Unit of Work class responsible for DB transactions  
  16.     ///</summary>  
  17.     publicclassUnitOfWork: IDisposable,  
  18.     IUnitOfWork  
  19.     {  
  20.       #region Private member variables...  
  21.   
  22.         privatereadonlyWebApiDbEntities _context = null;  
  23.         privateGenericRepository < User > _userRepository;  
  24.         privateGenericRepository < Product > _productRepository;  
  25.         privateGenericRepository < Token > _tokenRepository;#  
  26.         endregion  
  27.   
  28.         public UnitOfWork()   
  29.         {  
  30.             _context = newWebApiDbEntities();  
  31.         }  
  32.  
  33.         #region Public Repository Creation properties...  
  34.   
  35.         ///<summary>  
  36.         /// Get/Set Property for product repository.  
  37.         ///</summary>  
  38.         publicGenericRepository < Product > ProductRepository  
  39.         {  
  40.             get  
  41.             {  
  42.                 if (this._productRepository == null)  
  43.                     this._productRepository = newGenericRepository < Product > (_context);  
  44.                 return _productRepository;  
  45.             }  
  46.         }  
  47.   
  48.         ///<summary>  
  49.         /// Get/Set Property for user repository.  
  50.         ///</summary>  
  51.         publicGenericRepository < User > UserRepository  
  52.         {  
  53.             get  
  54.             {  
  55.                 if (this._userRepository == null)  
  56.                     this._userRepository = newGenericRepository < User > (_context);  
  57.                 return _userRepository;  
  58.             }  
  59.         }  
  60.   
  61.         ///<summary>  
  62.         /// Get/Set Property for token repository.  
  63.         ///</summary>  
  64.         publicGenericRepository < Token > TokenRepository  
  65.         {  
  66.             get  
  67.             {  
  68.                 if (this._tokenRepository == null)  
  69.                     this._tokenRepository = newGenericRepository < Token > (_context);  
  70.                 return _tokenRepository;  
  71.             }  
  72.         }#endregion  
  73.  
  74.         # region Public member methods...  
  75.             ///<summary>  
  76.             ///Save method.  
  77.             ///</summary>  
  78.         publicvoid Save()  
  79.         {  
  80.             try   
  81.             {  
  82.                 _context.SaveChanges();  
  83.             } catch (DbEntityValidationException e)  
  84.             {  
  85.   
  86.                 var outputLines = newList < string > ();  
  87.                 foreach(var eve in e.EntityValidationErrors)  
  88.                 {  
  89.                     outputLines.Add(string.Format("{0}: Entity of type \"{1}\" in state \"{2}\" has the following validation errors:", DateTime.Now, eve.Entry.Entity.GetType().Name, eve.Entry.State));  
  90.                     foreach(var ve in eve.ValidationErrors)  
  91.                     {  
  92.                         outputLines.Add(string.Format("- Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage));  
  93.                     }  
  94.                 }  
  95.                 System.IO.File.AppendAllLines(@ "C:\errors.txt", outputLines);  
  96.   
  97.                 throw e;  
  98.             }  
  99.   
  100.         }  
  101.  
  102.         #endregion  
  103.  
  104.         # region Implementing IDiosposable...  
  105.  
  106.         #region private dispose variable declaration...  
  107.         privatebool disposed = false;#  
  108.         endregion  
  109.   
  110.         ///<summary>  
  111.         /// Protected Virtual Dispose method  
  112.         ///</summary>  
  113.         ///<param name="disposing"></param>  
  114.         protectedvirtualvoid Dispose(bool disposing)  
  115.         {  
  116.             if (!this.disposed)   
  117.             {  
  118.                 if (disposing)  
  119.                 {  
  120.                     Debug.WriteLine("UnitOfWork is being disposed");  
  121.                     _context.Dispose();  
  122.                 }  
  123.             }  
  124.             this.disposed = true;  
  125.         }  
  126.   
  127.         ///<summary>  
  128.         /// Dispose method  
  129.         ///</summary>  
  130.         publicvoid Dispose()   
  131.         {  
  132.             Dispose(true);  
  133.             GC.SuppressFinalize(this);  
  134.         }#endregion  
  135.     }  
  136. }  
So, now all the interface members defined in IUnitOfWork are implemented in UnitOfWork class,

 

 

  1. publicinterfaceIUnitOfWork   
  2. {  
  3.   #region Properties  
  4.     GenericRepository < Product > ProductRepository   
  5.     {  
  6.         get;  
  7.     }  
  8.     GenericRepository < User > UserRepository  
  9.     {  
  10.         get;  
  11.     }  
  12.     GenericRepository < Token > TokenRepository  
  13.     {  
  14.         get;  
  15.     }#endregion  
  16.  
  17.     # region Public methods  
  18.     ///<summary>  
  19.     ///Save method.  
  20.     ///</summary>  
  21.     void Save();#endregion  
  22. }  
Doing this will not change the functionality of our existing code, but we also need to update the business services with this Interface. We’ll pass this IUnitOfWork interface instance inside services constructors instead of directly using UnitOfWork class.
  1. privatereadonlyIUnitOfWork _unitOfWork;  
  2.   
  3. public ProductServices(IUnitOfWork unitOfWork)  
  4. {  
  5.     _unitOfWork = unitOfWork;  
  6. }  
So our User service, Token service and product service constructors becomes as shown below,

Product Service:

code

User Service:

code

Token Service:

token

Testing Business Services

We’ll start writing unit tests for BusinessServices project.

Step 1: Test Project

Add a simple class library in the existing visual studio and name it BusinessServices.Tests. Open Tools->Library Packet Manager->Packet manager Console to open the package manager console window. We need to install come packages before we proceed.

test

Step 2: Install NUnit package

In package manager console, select BusinessServices.Tests as default project and write command “Install-Package NUnit –Version 2.6.4”. If you do not mention the version, the PMC (Package manage Console) will try to download the latest version of NUnit nugget package but we specifically need 2.6.4, so we need to mention the version. Same applies to when you try to install any such package from PMC.

manager

After successfully installed, you can see the dll reference in project references i.e. nunit.framework,

framework

Step 3: Install Moq framework

Install the framework on the same project in the similar way as explained in Step 2. Write command “Install-Package Moq” .Here we use latest version of Moq.

version

Therefore added dll,

dll

Step 4: Install Entity Framework

Install-Package EntityFramework–Version 5.0.0

Step 5: Install AutoMapper

Install-Package AutoMapper –Version 3.3.1

Our package.config i.e. automatically added in the project looks like,
  1. <?xmlversion="1.0"encoding="utf-8"?>  
  2. <packages>  
  3. <packageid="AutoMapper"version="3.3.1"targetFramework="net40" />  
  4. <packageid="EntityFramework"version="5.0.0"targetFramework="net40" />  
  5. <packageid="Moq"version="4.2.1510.2205"targetFramework="net40" />  
  6. <packageid="NUnit"version="2.6.4"targetFramework="net40" />  
  7. </packages>  
Step 6: References

Add references of DataModel, BusinessServices , BusinessEntities project to this project.

refrence

TestHelper

We will require few helper files that would be needed in BusinessServices.Tests project and in our WebAPI.Tests project that we’ll create later. To place all the helper files, I have created one more class library project named TestHelper. Just right click the solution and add new project named TestHelper and add a class named DataInitializer.cs into it. This class contains three simple methods to fetch i.e. User’s, Product’s and Token’s dummy data. You can use the following code as the class implementation,
  1. using System;  
  2. using System.Collections.Generic;  
  3. using DataModel;  
  4.   
  5. namespace TestsHelper  
  6. {  
  7.     ///<summary>  
  8.     /// Data initializer for unit tests  
  9.     ///</summary>  
  10.     publicclassDataInitializer  
  11.     {  
  12.         ///<summary>  
  13.         /// Dummy products  
  14.         ///</summary>  
  15.         ///<returns></returns>  
  16.         publicstaticList < Product > GetAllProducts()  
  17.         {  
  18.             var products = newList < Product >   
  19.                 {  
  20.                 newProduct()  
  21.                 {  
  22.                     ProductName = "Laptop"  
  23.                 },  
  24.                 newProduct()   
  25.                 {  
  26.                     ProductName = "Mobile"  
  27.                 },  
  28.                 newProduct()   
  29.                 {  
  30.                     ProductName = "HardDrive"  
  31.                 },  
  32.                 newProduct()  
  33.                 {  
  34.                     ProductName = "IPhone"  
  35.                 },  
  36.                 newProduct()  
  37.                 {  
  38.                     ProductName = "IPad"  
  39.                 }  
  40.             };  
  41.             return products;  
  42.         }  
  43.   
  44.         ///<summary>  
  45.         /// Dummy tokens  
  46.         ///</summary>  
  47.         ///<returns></returns>  
  48.         publicstaticList < Token > GetAllTokens()   
  49.         {  
  50.             var tokens = newList < Token >  
  51.                 {  
  52.                 newToken()  
  53.                   {  
  54.                     AuthToken = "9f907bdf-f6de-425d-be5b-b4852eb77761",  
  55.                         ExpiresOn = DateTime.Now.AddHours(2),  
  56.                         IssuedOn = DateTime.Now,  
  57.                         UserId = 1  
  58.                 },  
  59.                 newToken()  
  60.                   {  
  61.                     AuthToken = "9f907bdf-f6de-425d-be5b-b4852eb77762",  
  62.                         ExpiresOn = DateTime.Now.AddHours(1),  
  63.                         IssuedOn = DateTime.Now,  
  64.                         UserId = 2  
  65.                 }  
  66.             };  
  67.   
  68.             return tokens;  
  69.         }  
  70.   
  71.         ///<summary>  
  72.         /// Dummy users  
  73.         ///</summary>  
  74.         ///<returns></returns>  
  75.         publicstaticList < User > GetAllUsers()   
  76.         {  
  77.             var users = newList < User >   
  78.                 {  
  79.                 newUser()  
  80.                   {  
  81.                     UserName = "akhil",  
  82.                         Password = "akhil",  
  83.                         Name = "Akhil Mittal",  
  84.                 },  
  85.                 newUser()   
  86.                 {  
  87.                     UserName = "arsh",  
  88.                         Password = "arsh",  
  89.                         Name = "Arsh Mittal",  
  90.                 },  
  91.                 newUser()  
  92.                 {  
  93.                     UserName = "divit",  
  94.                         Password = "divit",  
  95.                         Name = "Divit Agarwal",  
  96.                 }  
  97.             };  
  98.   
  99.             return users;  
  100.         }  
  101.   
  102.     }  
  103. }  
In the above class GetAllUsers() fetches dummy data for users, GetAllProducts() fetches dummy data for Products and GetAllTokens() method fetches dummy data for Tokens. So now, our solution has two new projects as shown below,

project

Add DataModel project reference to TestHelper project and TestHelper project reference to BusinessServices.Tests project.

datamodel

webapi

ProductServiceTests

We’ll start with setting up the project and setting up the pre-requisites for tests and gradually move on to actual tests.

Tests Setup

We’ll proceed with creatingProductServices tests. Add a new class named ProductServicesTests.cs in BusinessServices.Tests project.

Declare variables

Define the private variables that we’ll use in the class to write tests,
  1. #region Variables  
  2. privateIProductServices _productService;  
  3. privateIUnitOfWork _unitOfWork;  
  4. privateList<Product> _products;  
  5. privateGenericRepository<Product> _productRepository;  
  6. privateWebApiDbEntities _dbEntities;  
  7. #endregion  
Variable declarations are self-explanatory where _productService will hold mock for ProductServices, _unitOfWork for UnitOfWork class, _products will hold dummy products from DataInitializer class of TestHelper project, _productRepository and _dbEntities holds mock for Product Repository and WebAPIDbEntities from DataModel project respectively

Write Test Fixture Setup

Test fixture setup is written as a onetime setup for all the tests. It is like a constructor in terms of classes. When we start executing setup, this is the first method to be executed. In this method we’ll populate the dummy products data and decorate this method with the [TestFixtureSetUp] attribute at the top that tells compiler that the particular method is a TestFixtureSetup. [TestFixtureSetUp] attribute is the part of NUnit framework, soinclude it in the class as a namespace i.e. using NUnit.Framework;. The following is the code for TestFixtureSetup.
  1. #region Test fixture setup  
  2.   
  3. ///<summary>  
  4. /// Initial setup for tests  
  5. ///</summary>  
  6.     [TestFixtureSetUp]  
  7. publicvoid Setup()  
  8. {  
  9.     _products = SetUpProducts();  
  10. }  
  11.  
  12. #endregion  
  13.   
  14. privatestaticList < Product > SetUpProducts()  
  15. {  
  16.     var prodId = newint();  
  17.     var products = DataInitializer.GetAllProducts();  
  18.     foreach(Product prod in products)  
  19.     prod.ProductId = ++prodId;  
  20.     return products;  
  21.   
  22. }  
SetUpproducts() method fetches products from DataInitializer class and not from database.It also and assigns a unique id to each product by iterating them.The result data is assigned to _products list to be used in setting up mock repository and in every individual test for comparison of actual vs resultant output.

Write Test Fixture Tear Down

Unlike TestFixtureSetup, tear down is used to de-allocate or dispose the objects.It also executes only one time when all the tests execution ends. In our case we’ll use this method to nullify _products instance. The attribute used for Test fixture tear down is [TestFixtureTearDown].

The following is the code for teardown.
  1. #region TestFixture TearDown.  
  2.   
  3. ///<summary>  
  4. /// TestFixture teardown  
  5. ///</summary>  
  6. [TestFixtureTearDown]  
  7. publicvoid DisposeAllObjects()  
  8. {  
  9. _products = null;  
  10. }  
  11.  
  12. #endregion  
Note that we have till now not written any unit test.

Write Test Setup

TestFixtureSetUpis a onetime run process where as [SetUp] marked method is executed after each test. Each test should be independent and should be tested with a fresh set of input. Setup helps us to re-initialize data for each test.Therefore all the required initialization for tests are written in this particular method marked with [SetUp] attribute. I have written few methods and initialized the private variables in this method.These lines of code execute after each test ends, so that individual tests do not depend on any other written test and do not get hampered with other tests pass or fail status. Code for Setup,
  1. #region Setup  
  2. ///<summary>  
  3. /// Re-initializes test.  
  4. ///</summary>  
  5.     [SetUp]  
  6. publicvoid ReInitializeTest()  
  7. {  
  8.     _dbEntities = newMock < WebApiDbEntities > ().Object;  
  9.     _productRepository = SetUpProductRepository();  
  10.     var unitOfWork = newMock < IUnitOfWork > ();  
  11.     unitOfWork.SetupGet(s => s.ProductRepository).Returns(_productRepository);  
  12.     _unitOfWork = unitOfWork.Object;  
  13.     _productService = newProductServices(_unitOfWork);  
  14. }  
  15.  
  16. #endregion  
We make use of Mock framework in this method to mock the private variable instances. Like for _dbEntities we write _dbEntities = newMock<WebApiDbEntities>().Object; . This means that we are mocking WebDbEntities class and getting its proxy object. Mock class is the class from Moq framework, so include the respective namespace using Moq; in the class

Write Test Tear down

Like testSetup runs after every test, similarly Test [TearDown] is invoked after every test execution is complete.You can use tear down to dispose and nullify the objects that are initialized while setup.The method for tear down should be decorated with [TearDown]attribute. The following is the test tear down implementation.
  1. ///<summary>  
  2. /// Tears down each test data  
  3. ///</summary>  
  4. [TearDown]  
  5. publicvoid DisposeTest()  
  6. {  
  7.     _productService = null;  
  8.     _unitOfWork = null;  
  9.     _productRepository = null;  
  10.     if (_dbEntities != null)  
  11.         _dbEntities.Dispose();  
  12. }  
Mocking Repository

I talked about mocking repository for the entities. I have created a method SetUpProductRepository() to mock Product Repository and assign it to _productrepository in ReInitializeTest() method.
  1. privateGenericRepository < Product > SetUpProductRepository()   
  2. {  
  3.   
  4.     // Initialise repository  
  5.     var mockRepo = newMock < GenericRepository < Product >> (MockBehavior.Default, _dbEntities);  
  6.   
  7.     // Setup mocking behavior  
  8.     mockRepo.Setup(p => p.GetAll()).Returns(_products);  
  9.   
  10.     mockRepo.Setup(p => p.GetByID(It.IsAny < int > ()))  
  11.         .Returns(newFunc < int, Product > (  
  12.             id => _products.Find(p => p.ProductId.Equals(id))));  
  13.   
  14.     mockRepo.Setup(p => p.Insert((It.IsAny < Product > ())))  
  15.         .Callback(newAction < Product > (newProduct => {  
  16.             dynamic maxProductID = _products.Last().ProductId;  
  17.             dynamic nextProductID = maxProductID + 1;  
  18.             newProduct.ProductId = nextProductID;  
  19.             _products.Add(newProduct);  
  20.         }));  
  21.   
  22.     mockRepo.Setup(p => p.Update(It.IsAny < Product > ()))  
  23.         .Callback(newAction < Product > (prod =>  
  24.         {  
  25.             var oldProduct = _products.Find(a => a.ProductId == prod.ProductId);  
  26.             oldProduct = prod;  
  27.         }));  
  28.   
  29.     mockRepo.Setup(p => p.Delete(It.IsAny < Product > ()))  
  30.         .Callback(newAction < Product > (prod =>  
  31.         {  
  32.             var productToRemove =  
  33.                 _products.Find(a => a.ProductId == prod.ProductId);  
  34.   
  35.             if (productToRemove != null)  
  36.                 _products.Remove(productToRemove);  
  37.         }));  
  38.   
  39.     // Return mock implementation object  
  40.     return mockRepo.Object;  
  41. }  
Here we mock all the required methods of Product Repository to get the desired data from _products object and not from actual database.

The single line of code var mockRepo = newMock<GenericRepository<Product>>(MockBehavior.Default, _dbEntities);
mocks the Generic Repository for Product and mockRepo.Setup() mocks the repository methods by passing relevant delegates to the method.

Initialize UnitOfWork and Service


I have written the following lines of code in ReInitializeTest() method i.e. our setup method,
  1. var unitOfWork = newMock<IUnitOfWork>();  
  2. unitOfWork.SetupGet(s => s.ProductRepository).Returns(_productRepository);  
  3. _unitOfWork = unitOfWork.Object;  
  4. _productService = newProductServices(_unitOfWork);  
Here you can see that I am trying to mock the UnitOfWork instance and forcing it to perform all its transactions and operations on _productRepository that we have mocked earlier. This means that all the transactions will be limited to the mocked repository and actual database or actual repository will not be touched. Same goes for service as well; we are initializing product Services with this mocked _unitOfWork. So when we use _productService in actual tests, it actually works on mocked UnitOfWork and test data only.

test

All set now and we are ready to write unit tests for ProductService. We’ll write test to perform all the CRUD operations that are part of ProductService.

 

  1. GetAllProductsTest ()

    Our ProductService in BusinessServices project contains a method named GetAllProducts (), the following is the implementation,
    1. publicIEnumerable < BusinessEntities.ProductEntity > GetAllProducts()  
    2. {  
    3.     var products = _unitOfWork.ProductRepository.GetAll().ToList();  
    4.     if (products.Any())  
    5.     {  
    6.         Mapper.CreateMap < Product, ProductEntity > ();  
    7.         var productsModel = Mapper.Map < List < Product > ,  
    8.             List < ProductEntity >> (products);  
    9.         return productsModel;  
    10.     }  
    11.     returnnull;  
    12. }  
    We see here, that this method fetches all the available products from the database, maps the database entity to our custom BusinessEntities.ProductEntity and returns the list of custom BusinessEntities.ProductEntity. It returns null if no products are found.

    To start writing a test method, you need to decorate that test method with [Test] attribute of NUnit framework. This attribute specifies that particular method is a Unit Test method.

    The following is the unit test method I have written for the above mentioned business service method,
    1. [Test]  
    2. publicvoid GetAllProductsTest()   
    3. {  
    4.     var products = _productService.GetAllProducts();  
    5.     var productList =  
    6.         products.Select(  
    7.             productEntity =>  
    8.             newProduct {  
    9.                 ProductId = productEntity.ProductId, ProductName = productEntity.ProductName  
    10.             }).ToList();  
    11.     var comparer = newProductComparer();  
    12.     CollectionAssert.AreEqual(  
    13.         productList.OrderBy(product => product, comparer),  
    14.         _products.OrderBy(product => product, comparer), comparer);  
    15. }  
    We used instance of _productService and called the GetAllProducts() method, that will ultimately execute on mocked UnitOfWork and Repository to fetch test data from _products list. The products returned from the method are of type BusinessEntities.ProductEntity and we need to compare the returned products with our existing _products list i.e. the list of DataModel.Product i.e. a mocked database entity, so we need to convert the returned BusinessEntities.ProductEntity list to DataModel.Product list. We do this with the following line of code,
    1. var productList =  
    2. products.Select(  
    3. productEntity =>  
    4. newProduct {ProductId = productEntity.ProductId, ProductName = productEntity.ProductName}).ToList();  
    Now we got two lists to compare, one _products list i.e. the actual products and another productList i.e. the products returned from the service. I have written a helper class and compare method to convert the two Product list in TestHelper project. This method checks the list items and compares them for equality of values. You can add a class named ProductComparer to TestHelper project with the following implementations,
    1. publicclassProductComparer: IComparer, IComparer < Product >  
    2.   {  
    3.     publicint Compare(object expected, object actual)   
    4.   {  
    5.         var lhs = expected asProduct;  
    6.         var rhs = actual asProduct;  
    7.         if (lhs == null || rhs == null) thrownewInvalidOperationException();  
    8.         return Compare(lhs, rhs);  
    9.     }  
    10.   
    11.     publicint Compare(Product expected, Product actual)  
    12.     {  
    13.         int temp;  
    14.         return (temp = expected.ProductId.CompareTo(actual.ProductId)) != 0 ? temp : expected.ProductName.CompareTo(actual.ProductName);  
    15.     }  
    16. }  
    To assert the result we use CollectionAssert.AreEqual of NUnit where we pass both the lists and comparer.
    1. CollectionAssert.AreEqual(  
    2. productList.OrderBy(product => product, comparer),  
    3. _products.OrderBy(product => product, comparer), comparer);  
    Since I have NUnit plugin in my visual studio provided by Resharper, let me debug the test method to see the actual result of Assert. We’ll run all the tests with NUnit UI at the end of the article.

    allproducts

    productList ,

    productlist

    _products,

    products

    We got both the list, and we need to check the comparison of the lists, I just pressed F5 and got the result on TestUI as,

    session

    This shows our test is passed, i.e. the expected and returned result is same.

  2. GetAllProductsTestForNull ()

    You can also write the test for null check for the same method where you nullify the _products list before you invoke the service method. We actually need to write tests that cover all the exit points of the invoked method.

    The following test covers another exit point of the method that returns null in case of no products found.
    1. ///<summary>  
    2. /// Service should return null  
    3. ///</summary>  
    4. [Test]  
    5. publicvoid GetAllProductsTestForNull()  
    6. {  
    7.     _products.Clear();  
    8.     var products = _productService.GetAllProducts();  
    9.     Assert.Null(products);  
    10.     SetUpProducts();  
    11. }  
    In above mentioned test, we first clear the _products list and invoke the service method. Now assert the result for null because our expected result and actual result should be null. I called the SetUpProducts() method again to populate the _products list, but you can do this in test setup method as well i.e. ReInitializeTest().

    session

    Now let’s move to other tests.

  3. GetProductByRightIdTest ()

    Here we test GetProductById() method of ProductService. Ideal behavior is that if I invoke the method with a valid id, the method should return the valid product. Now let’s suppose I know the product id for my product named “Mobile” and I invoke the test using that id, so ideally I should get a product with the product name mobile.
    1. ///<summary>  
    2. /// Service should return product if correct id is supplied  
    3. ///</summary>  
    4. [Test]  
    5. publicvoid GetProductByRightIdTest()  
    6. {  
    7.     var mobileProduct = _productService.GetProductById(2);  
    8.     if (mobileProduct != null)   
    9.     {  
    10.         Mapper.CreateMap < ProductEntity, Product > ();  
    11.         var productModel = Mapper.Map < ProductEntity,  
    12.             Product > (mobileProduct);  
    13.         AssertObjects.PropertyValuesAreEquals(productModel,  
    14.             _products.Find(a => a.ProductName.Contains("Mobile")));  
    15.     }  
    16. }  
    The above code is self-explanatory except the line AssertObjects.PropertyValuesAreEquals.

    _productService.GetProductById(2); line fetches the product with product id 2.
    1. Mapper.CreateMap<ProductEntity, Product>();  
    2. var productModel = Mapper.Map<ProductEntity, Product>(mobileProduct);  
    Above code maps the returned custom ProductEntity to DataModel.Product

    AssertObjectsis one more class I have added inside TestHelper class. The purpose of this class is to compare the properties of two objects. This is a common generic class applicable for all type of class objects having properties. Its method PropertyValuesAreEquals() checks for equality of the properties.

    AssertObjects class:
    1. using System.Collections;  
    2. using System.Reflection;  
    3. using NUnit.Framework;  
    4.   
    5. namespace TestsHelper   
    6. {  
    7.     publicstaticclassAssertObjects  
    8.     {  
    9.         publicstaticvoid PropertyValuesAreEquals(object actual, object expected)   
    10.         {  
    11.             PropertyInfo[] properties = expected.GetType().GetProperties();  
    12.             foreach(PropertyInfo property in properties)  
    13.             {  
    14.                 object expectedValue = property.GetValue(expected, null);  
    15.                 object actualValue = property.GetValue(actual, null);  
    16.   
    17.                 if (actualValue isIList)  
    18.                     AssertListsAreEquals(property, (IList) actualValue, (IList) expectedValue);  
    19.                 elseif(!Equals(expectedValue, actualValue))  
    20.                 if (property.DeclaringType != null)  
    21.                     Assert.Fail("Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name, expectedValue, actualValue);  
    22.             }  
    23.         }  
    24.   
    25.         privatestaticvoid AssertListsAreEquals(PropertyInfo property, IList actualList, IList expectedList) {  
    26.             if (actualList.Count != expectedList.Count)  
    27.                 Assert.Fail("Property {0}.{1} does not match. Expected IList containing {2} elements but was IList containing {3} elements", property.PropertyType.Name, property.Name, expectedList.Count, actualList.Count);  
    28.   
    29.             for (int i = 0; i < actualList.Count; i++)  
    30.                 if (!Equals(actualList[i], expectedList[i]))  
    31.                     Assert.Fail("Property {0}.{1} does not match. Expected IList with element {1} equals to {2} but was IList with element {1} equals to {3}", property.PropertyType.Name, property.Name, expectedList[i], actualList[i]);  
    32.         }  
    33.     }  
    34. }  
    Running the test,

    test
    session

  4. GetProductByWrongIdTest ()

    In this test we test the service method with wrong id and expect null in return.
    1. ///<summary>  
    2. /// Service should return null  
    3. ///</summary>  
    4. [Test]  
    5. publicvoid GetProductByWrongIdTest()   
    6. {  
    7.     var product = _productService.GetProductById(0);  
    8.     Assert.Null(product);  
    9. }  
    session

  5. AddNewProductTest ()

    In this unit test we test the CreateProduct() method of ProductService. The following is the unit test written for creating a new product.
    1. ///<summary>  
    2. /// Add new product test  
    3. ///</summary>  
    4. [Test]  
    5. publicvoid AddNewProductTest()  
    6. {  
    7.     var newProduct = newProductEntity()   
    8.     {  
    9.         ProductName = "Android Phone"  
    10.     };  
    11.   
    12.     var maxProductIDBeforeAdd = _products.Max(a => a.ProductId);  
    13.     newProduct.ProductId = maxProductIDBeforeAdd + 1;  
    14.     _productService.CreateProduct(newProduct);  
    15.     var addedproduct = newProduct()  
    16.     {  
    17.         ProductName = newProduct.ProductName, ProductId = newProduct.ProductId  
    18.     };  
    19.     AssertObjects.PropertyValuesAreEquals(addedproduct, _products.Last());  
    20.     Assert.That(maxProductIDBeforeAdd + 1, Is.EqualTo(_products.Last().ProductId));  
    21. }  
    In above code I have created a dummy product with product name “Android Phone” and assigned the product id as the incremented id to the maximum value of productId of the product that lies in _products list. Ideally if my test is success, the added product should reflect in _products list as last product with maximum product id. To verify the result, I have used two asserts, first one checks the properties of expected and actual product and second one verifies the product id.

    var addedproduct = newProduct() {ProductName = newProduct.ProductName, ProductId = newProduct.ProductId};

    addedProduct is the custom product that is expected to be added in the _products list and _products.Last() gives us last product of the list. So,

    AssertObjects.PropertyValuesAreEquals(addedproduct, _products.Last()); checks for all the properties of dummy as well as last added product and,

    Assert.That(maxProductIDBeforeAdd + 1, Is.EqualTo(_products.Last().ProductId)); checks if the last product added has the same product id as supplied while creating the product.

    test
    test

    After full execution,

    session

    The test passes, that means the expected value that was product id 6 was equal to the product id of the last added product in _products list. And we can also see that, earlier we had only 5 products in _products list and now we have added a 6th one.

  6. UpdateProductTest ()

    This is the unit test to check if the product is updated or not. This test is for UpdateProduct() method of ProductService.
    1. ///<summary>  
    2. /// Update product test  
    3. ///</summary>  
    4. [Test]  
    5. publicvoid UpdateProductTest()   
    6. {  
    7.     var firstProduct = _products.First();  
    8.     firstProduct.ProductName = "Laptop updated";  
    9.     var updatedProduct = newProductEntity()  
    10.     {  
    11.         ProductName = firstProduct.ProductName, ProductId = firstProduct.ProductId  
    12.     };  
    13.     _productService.UpdateProduct(firstProduct.ProductId, updatedProduct);  
    14.     Assert.That(firstProduct.ProductId, Is.EqualTo(1)); // hasn't changed  
    15.     Assert.That(firstProduct.ProductName, Is.EqualTo("Laptop updated")); // Product name changed  
    16.   
    17. }  
    In this test I am trying to update first product from _products list. I have changed the product name to “Laptop Updated” and invoked the UpdateProduct() method of ProductService. I have made two asserts to check the updated product from _products list, one for productId and second for product name. We see that we get the updated product while we assert.

    test
    session
  7. DeleteProductTest ()

    The following is the test for DeleteProduct() method in ProductService.
    1. ///<summary>  
    2. /// Delete product test  
    3. ///</summary>  
    4. [Test]  
    5. publicvoid DeleteProductTest()  
    6. {  
    7.     int maxID = _products.Max(a => a.ProductId); // Before removal  
    8.     var lastProduct = _products.Last();  
    9.   
    10.     // Remove last Product  
    11.     _productService.DeleteProduct(lastProduct.ProductId);  
    12.     Assert.That(maxID, Is.GreaterThan(_products.Max(a => a.ProductId))); // Max id reduced by 1  
    13. }  
    I have written the test to verify the max id of product from the list of products. Get max id of the product, delete the last product and check the max id of the product from the list. The prior max id should be greater than the last product’s product id.

    test
    test

      Max id before delete was 5 and after delete is 4 that means a product is deleted from _products list therefore statement : Assert.That(maxID, Is.GreaterThan(_products.Max(a => a.ProductId))); passes as 5 is greater than 4.

    authenticate

We have covered all the methods of ProductService under unit tests. The following is the final class that covers all the tests for this service.

  1. #region using namespaces.  
  2. using System;  
  3. using System.Collections.Generic;  
  4. using System.Linq;  
  5. using AutoMapper;  
  6. using BusinessEntities;  
  7. using DataModel;  
  8. using DataModel.GenericRepository;  
  9. using DataModel.UnitOfWork;  
  10. using Moq;  
  11. using NUnit.Framework;  
  12. using TestsHelper;  
  13.  
  14. #endregion  
  15.   
  16. namespace BusinessServices.Tests  
  17. {  
  18.     ///<summary>  
  19.     /// Product Service Test  
  20.     ///</summary>  
  21.     publicclassProductServicesTest  
  22.     {  
  23.       #region Variables  
  24.   
  25.         privateIProductServices _productService;  
  26.         privateIUnitOfWork _unitOfWork;  
  27.         privateList < Product > _products;  
  28.         privateGenericRepository < Product > _productRepository;  
  29.         privateWebApiDbEntities _dbEntities;#  
  30.         endregion  
  31.  
  32.         #region Test fixture setup  
  33.   
  34.         ///<summary>  
  35.         /// Initial setup for tests  
  36.         ///</summary>  
  37.             [TestFixtureSetUp]  
  38.         publicvoid Setup() {  
  39.             _products = SetUpProducts();  
  40.         }  
  41.  
  42.         #endregion  
  43.  
  44.         #region Setup  
  45.   
  46.         ///<summary>  
  47.         /// Re-initializes test.  
  48.         ///</summary>  
  49.             [SetUp]  
  50.         publicvoid ReInitializeTest()  
  51.         {  
  52.             _dbEntities = newMock < WebApiDbEntities > ().Object;  
  53.             _productRepository = SetUpProductRepository();  
  54.             var unitOfWork = newMock < IUnitOfWork > ();  
  55.             unitOfWork.SetupGet(s => s.ProductRepository).Returns(_productRepository);  
  56.             _unitOfWork = unitOfWork.Object;  
  57.             _productService = newProductServices(_unitOfWork);  
  58.         }  
  59.  
  60.         #endregion  
  61.  
  62.         #region Private member methods  
  63.   
  64.         ///<summary>  
  65.         /// Setup dummy repository  
  66.         ///</summary>  
  67.         ///<returns></returns>  
  68.         privateGenericRepository < Product > SetUpProductRepository()  
  69.         {  
  70.             // Initialise repository  
  71.             var mockRepo = newMock < GenericRepository < Product >> (MockBehavior.Default, _dbEntities);  
  72.   
  73.             // Setup mocking behavior  
  74.             mockRepo.Setup(p => p.GetAll()).Returns(_products);  
  75.   
  76.             mockRepo.Setup(p => p.GetByID(It.IsAny < int > ()))  
  77.                 .Returns(newFunc < int, Product > (  
  78.                     id => _products.Find(p => p.ProductId.Equals(id))));  
  79.   
  80.             mockRepo.Setup(p => p.Insert((It.IsAny < Product > ())))  
  81.                 .Callback(newAction < Product > (newProduct =>   
  82.                 {  
  83.                     dynamic maxProductID = _products.Last().ProductId;  
  84.                     dynamic nextProductID = maxProductID + 1;  
  85.                     newProduct.ProductId = nextProductID;  
  86.                     _products.Add(newProduct);  
  87.                 }));  
  88.   
  89.             mockRepo.Setup(p => p.Update(It.IsAny < Product > ()))  
  90.                 .Callback(newAction < Product > (prod =>   
  91.                 {  
  92.                     var oldProduct = _products.Find(a => a.ProductId == prod.ProductId);  
  93.                     oldProduct = prod;  
  94.                 }));  
  95.   
  96.             mockRepo.Setup(p => p.Delete(It.IsAny < Product > ()))  
  97.                 .Callback(newAction < Product > (prod =>   
  98.                 {  
  99.                     var productToRemove =  
  100.                         _products.Find(a => a.ProductId == prod.ProductId);  
  101.   
  102.                     if (productToRemove != null)  
  103.                         _products.Remove(productToRemove);  
  104.                 }));  
  105.   
  106.             // Return mock implementation object  
  107.             return mockRepo.Object;  
  108.         }  
  109.   
  110.         ///<summary>  
  111.         /// Setup dummy products data  
  112.         ///</summary>  
  113.         ///<returns></returns>  
  114.         privatestaticList < Product > SetUpProducts() {  
  115.             var prodId = newint();  
  116.             var products = DataInitializer.GetAllProducts();  
  117.             foreach(Product prod in products)  
  118.             prod.ProductId = ++prodId;  
  119.             return products;  
  120.   
  121.         }  
  122.  
  123.         #endregion  
  124.  
  125.         #region Unit Tests  
  126.   
  127.         ///<summary>  
  128.         /// Service should return all the products  
  129.         ///</summary>  
  130.             [Test]  
  131.         publicvoid GetAllProductsTest()  
  132.         {  
  133.             var products = _productService.GetAllProducts();  
  134.             if (products != null)  
  135.             {  
  136.                 var productList =  
  137.                     products.Select(  
  138.                         productEntity =>  
  139.                         newProduct {  
  140.                             ProductId = productEntity.ProductId, ProductName = productEntity.ProductName  
  141.                         }).  
  142.                 ToList();  
  143.                 var comparer = newProductComparer();  
  144.                 CollectionAssert.AreEqual(  
  145.                     productList.OrderBy(product => product, comparer),  
  146.                     _products.OrderBy(product => product, comparer), comparer);  
  147.             }  
  148.         }  
  149.   
  150.         ///<summary>  
  151.         /// Service should return null  
  152.         ///</summary>  
  153.         [Test]  
  154.         publicvoid GetAllProductsTestForNull()  
  155.         {  
  156.             _products.Clear();  
  157.             var products = _productService.GetAllProducts();  
  158.             Assert.Null(products);  
  159.             SetUpProducts();  
  160.         }  
  161.   
  162.         ///<summary>  
  163.         /// Service should return product if correct id is supplied  
  164.         ///</summary>  
  165.         [Test]  
  166.         publicvoid GetProductByRightIdTest()   
  167.         {  
  168.             var mobileProduct = _productService.GetProductById(2);  
  169.             if (mobileProduct != null)   
  170.             {  
  171.                 Mapper.CreateMap < ProductEntity, Product > ();  
  172.                 var productModel = Mapper.Map < ProductEntity,  
  173.                     Product > (mobileProduct);  
  174.                 AssertObjects.PropertyValuesAreEquals(productModel,  
  175.                     _products.Find(a => a.ProductName.Contains("Mobile")));  
  176.             }  
  177.         }  
  178.   
  179.         ///<summary>  
  180.         /// Service should return null  
  181.         ///</summary>  
  182.         [Test]  
  183.         publicvoid GetProductByWrongIdTest()   
  184.         {  
  185.             var product = _productService.GetProductById(0);  
  186.             Assert.Null(product);  
  187.         }  
  188.   
  189.         ///<summary>  
  190.         /// Add new product test  
  191.         ///</summary>  
  192.         [Test]  
  193.         publicvoid AddNewProductTest()  
  194.         {  
  195.             var newProduct = newProductEntity()  
  196.             {  
  197.                 ProductName = "Android Phone"  
  198.             };  
  199.   
  200.             var maxProductIDBeforeAdd = _products.Max(a => a.ProductId);  
  201.             newProduct.ProductId = maxProductIDBeforeAdd + 1;  
  202.             _productService.CreateProduct(newProduct);  
  203.             var addedproduct = newProduct()  
  204.             {  
  205.                 ProductName = newProduct.ProductName, ProductId = newProduct.ProductId  
  206.             };  
  207.             AssertObjects.PropertyValuesAreEquals(addedproduct, _products.Last());  
  208.             Assert.That(maxProductIDBeforeAdd + 1, Is.EqualTo(_products.Last().ProductId));  
  209.         }  
  210.   
  211.         ///<summary>  
  212.         /// Update product test  
  213.         ///</summary>  
  214.         [Test]  
  215.         publicvoid UpdateProductTest()  
  216.         {  
  217.             var firstProduct = _products.First();  
  218.             firstProduct.ProductName = "Laptop updated";  
  219.             var updatedProduct = newProductEntity()  
  220.             {  
  221.                 ProductName = firstProduct.ProductName, ProductId = firstProduct.ProductId  
  222.             };  
  223.             _productService.UpdateProduct(firstProduct.ProductId, updatedProduct);  
  224.             Assert.That(firstProduct.ProductId, Is.EqualTo(1)); // hasn't changed  
  225.             Assert.That(firstProduct.ProductName, Is.EqualTo("Laptop updated")); // Product name changed  
  226.         }  
  227.   
  228.         ///<summary>  
  229.         /// Delete product test  
  230.         ///</summary>  
  231.         [Test]  
  232.         publicvoid DeleteProductTest()  
  233.         {  
  234.             int maxID = _products.Max(a => a.ProductId); // Before removal  
  235.             var lastProduct = _products.Last();  
  236.   
  237.             // Remove last Product  
  238.             _productService.DeleteProduct(lastProduct.ProductId);  
  239.             Assert.That(maxID, Is.GreaterThan(_products.Max(a => a.ProductId))); // Max id reduced by 1  
  240.         }  
  241.  
  242.         #endregion  
  243.  
  244.  
  245.         # region Tear Down  
  246.   
  247.         ///<summary>  
  248.         /// Tears down each test data  
  249.         ///</summary>  
  250.             [TearDown]  
  251.         publicvoid DisposeTest()  
  252.         {  
  253.             _productService = null;  
  254.             _unitOfWork = null;  
  255.             _productRepository = null;  
  256.             if (_dbEntities != null)  
  257.                 _dbEntities.Dispose();  
  258.         }  
  259.  
  260.         #endregion  
  261.  
  262.         # region TestFixture TearDown.  
  263.   
  264.         ///<summary>  
  265.         /// TestFixture teardown  
  266.         ///</summary>  
  267.         [TestFixtureTearDown]  
  268.         publicvoid DisposeAllObjects()  
  269.         {  
  270.             _products = null;  
  271.         }  
  272.  
  273.         #endregion  
  274.     }  
  275. }  
TokenService Tests

Now that we have completed all the tests for ProductService, I am sure you must have got an idea on how to write unit tests for methods. Note that primarily unit tests are only written to publically exposed methods because the private methods automatically get tested through those public methods in the class. I’ll not explain too much theory for TokenService tests and only navigate through code. I’ll explain the details wherever necessary.

Tests Setup

Add a new class named TokenServicesTests.cs in BusinessServices.Tests project.

Declare variables

Define the private variable that we’ll use in the class to write tests,
  1. #region Variables  
  2. privateITokenServices _tokenServices;  
  3. privateIUnitOfWork _unitOfWork;  
  4. privateList<Token> _tokens;  
  5. privateGenericRepository<Token> _tokenRepository;  
  6. privateWebApiDbEntities _dbEntities;  
  7. privateconststring SampleAuthToken = "9f907bdf-f6de-425d-be5b-b4852eb77761";  
  8. #endregion  
Here _tokenService will hold mock for TokenServices, _unitOfWork for UnitOfWork class, __tokens will hold dummy tokens from DataInitializer class of TestHelper project, _tokenRepository and _dbEntities holds mock for Token Repository and WebAPIDbEntities from DataModel project respectively

Write Test Fixture Setup
  1. #region Test fixture setup
    ///<summary>
      
  2. /// Initial setup for tests  
  3. ///</summary>  
  4. [TestFixtureSetUp]  
  5. publicvoid Setup()  
  6. {  
  7. _tokens = SetUpTokens();  
  8. }  
  9.  
  10. #endregion  
SetUpTokens() method fetches tokens from DataInitializer class and not from database and assigns a unique id to each token by iterating on them.
  1. ///<summary>  
  2. /// Setup dummy tokens data  
  3. ///</summary>  
  4. ///<returns></returns>  
  5. privatestaticList < Token > SetUpTokens()   
  6. {  
  7.     var tokId = newint();  
  8.     var tokens = DataInitializer.GetAllTokens();  
  9.     foreach(Token tok in tokens)  
  10.     tok.TokenId = ++tokId;  
  11.     return tokens;  
  12. }  
The result data is assigned to __tokens list to be used in setting up mock repository and in every individual test for comparison of actual vs resultant output.

Write Test Fixture Tear Down
  1. #region TestFixture TearDown.  
  2.   
  3. ///<summary>  
  4. /// TestFixture teardown  
  5. ///</summary>  
  6. [TestFixtureTearDown]  
  7. publicvoid DisposeAllObjects()  
  8. {  
  9. _tokens = null;  
  10. }  
  11.  
  12. #endregion  
Write Test Setup
  1. #region Setup  
  2.   
  3. ///<summary>  
  4. /// Re-initializes test.  
  5. ///</summary>  
  6.     [SetUp]  
  7. publicvoid ReInitializeTest()  
  8. {  
  9.     _dbEntities = newMock < WebApiDbEntities > ().Object;  
  10.     _tokenRepository = SetUpTokenRepository();  
  11.     var unitOfWork = newMock < IUnitOfWork > ();  
  12.     unitOfWork.SetupGet(s => s.TokenRepository).Returns(_tokenRepository);  
  13.     _unitOfWork = unitOfWork.Object;  
  14.     _tokenServices = newTokenServices(_unitOfWork);  
  15. }  
  16.  
  17. #endregion  
Write Test Tear down
  1. #region Tear Down  
  2.   
  3. ///<summary>  
  4. /// Tears down each test data  
  5. ///</summary>  
  6.     [TearDown]  
  7. publicvoid DisposeTest()   
  8. {  
  9.     _tokenServices = null;  
  10.     _unitOfWork = null;  
  11.     _tokenRepository = null;  
  12.     if (_dbEntities != null)  
  13.         _dbEntities.Dispose();  
  14. }  
  15.  
  16. #endregion  
Mocking Repository
  1. privateGenericRepository < Token > SetUpTokenRepository()  
  2. {  
  3.     // Initialise repository  
  4.     var mockRepo = newMock < GenericRepository < Token >> (MockBehavior.Default, _dbEntities);  
  5.   
  6.     // Setup mocking behavior  
  7.     mockRepo.Setup(p => p.GetAll()).Returns(_tokens);  
  8.   
  9.     mockRepo.Setup(p => p.GetByID(It.IsAny < int > ()))  
  10.         .Returns(newFunc < int, Token > (  
  11.             id => _tokens.Find(p => p.TokenId.Equals(id))));  
  12.   
  13.     mockRepo.Setup(p => p.GetByID(It.IsAny < string > ()))  
  14.         .Returns(newFunc < string, Token > (  
  15.             authToken => _tokens.Find(p => p.AuthToken.Equals(authToken))));  
  16.   
  17.     mockRepo.Setup(p => p.Insert((It.IsAny < Token > ())))  
  18.         .Callback(newAction < Token > (newToken => {  
  19.             dynamic maxTokenID = _tokens.Last().TokenId;  
  20.             dynamic nextTokenID = maxTokenID + 1;  
  21.             newToken.TokenId = nextTokenID;  
  22.             _tokens.Add(newToken);  
  23.         }));  
  24.   
  25.     mockRepo.Setup(p => p.Update(It.IsAny < Token > ()))  
  26.         .Callback(newAction < Token > (token =>  
  27.          {  
  28.             var oldToken = _tokens.Find(a => a.TokenId == token.TokenId);  
  29.             oldToken = token;  
  30.         }));  
  31.   
  32.     mockRepo.Setup(p => p.Delete(It.IsAny < Token > ()))  
  33.         .Callback(newAction < Token > (prod =>  
  34.         {  
  35.             var tokenToRemove =  
  36.                 _tokens.Find(a => a.TokenId == prod.TokenId);  
  37.   
  38.             if (tokenToRemove != null)  
  39.                 _tokens.Remove(tokenToRemove);  
  40.         }));  
  41.     //Create setup for other methods too. note non virtauls methods can not be set up  
  42.   
  43.     // Return mock implementation object  
  44.     return mockRepo.Object;  
  45. }  
Note, while mocking repository, I have setup two mocks for GetById(). There is a minor change I did in the database, I have marked AuthToken field as a primary key too. So it may be a situation where mock gets confused on calling the method that for which primary key the request has been made. So I have implemented the mock both for TokenId and AuthToken field,
  1. mockRepo.Setup(p => p.GetByID(It.IsAny<int>())).Returns(newFunc<int, Token>(  
  2. id => _tokens.Find(p => p.TokenId.Equals(id))));  
  3.   
  4. mockRepo.Setup(p => p.GetByID(It.IsAny<string>())).Returns(newFunc<string, Token>(  
  5. authToken => _tokens.Find(p => p.AuthToken.Equals(authToken)))); 
The overall setup is of same nature as we wrote for ProductService. Let us move on to unit tests.

 

  1. GenerateTokenByUseridTest ()

    This unit test is to test the GenerateToken method of TokenServices business service. In this method a new token is generated in the database against a user. We’ll use _tokens list for all these transactions. Currently we have only two token entries in _tokens list generated from DataInitializer. Now when the test executes it should expect one more token to be added to the list.
    1. [Test]  
    2. publicvoid GenerateTokenByUserIdTest()   
    3. {  
    4.     constint userId = 1;  
    5.     var maxTokenIdBeforeAdd = _tokens.Max(a => a.TokenId);  
    6.     var tokenEntity = _tokenServices.GenerateToken(userId);  
    7.     var newTokenDataModel = newToken()  
    8.     {  
    9.         AuthToken = tokenEntity.AuthToken,  
    10.             TokenId = maxTokenIdBeforeAdd + 1,  
    11.             ExpiresOn = tokenEntity.ExpiresOn,  
    12.             IssuedOn = tokenEntity.IssuedOn,  
    13.             UserId = tokenEntity.UserId  
    14.     };  
    15.     AssertObjects.PropertyValuesAreEquals(newTokenDataModel, _tokens.Last());  
    16. }  
    I have taken a default user id as 1, and stored the max token id from the list of tokens. Call the service method GenerateTokenEntity(). Since our service method returns BusinessEntities.TokenEntity, we need to map it to new DataModel.Token object for comparison. So expected result is that all the properties of this token should match the last token of the _token list assuming that list is updated through the test.

    test
    lastentry

    Now since all the properties of the resultant and actual object match, so our test passes.

    session

  2. ValidateTokenWithRightAuthToken ()
    1. ///<summary>  
    2. /// Validate token test  
    3. ///</summary>  
    4. [Test]  
    5. publicvoid ValidateTokenWithRightAuthToken()   
    6. {  
    7.     var authToken = Convert.ToString(SampleAuthToken);  
    8.     var validationResult = _tokenServices.ValidateToken(authToken);  
    9.     Assert.That(validationResult, Is.EqualTo(true));  
    This test validates AuthToken through ValidateToken method of TokenService.Ideally if correct token is passed, the service should return true.

    token

    Here we get validationResult as true therefore test should pass.

    session

  3. ValidateTokenWithWrongAuthToken ()

    Testing same method for its alternate exit point, therefore with wrong token, the service should return false.
    1. [Test]  
    2. publicvoid ValidateTokenWithWrongAuthToken()   
    3. {  
    4.     var authToken = Convert.ToString("xyz");  
    5.     var validationResult = _tokenServices.ValidateToken(authToken);  
    6.     Assert.That(validationResult, Is.EqualTo(false));  
    7. }  
    Here validationResult is false, and is compared to false value, so test should ideally pass.

    validate

    UserService Tests

    I have tried writing unit tests for UserService as per our service implementations, but encountered an error while mocking up our repositories Get () method that takes predicate or where condition as a parameter.
    1. public TEntity Get(Func<TEntity, Boolean> where)  
    2. {  
    3. return DbSet.Where(where).FirstOrDefault<TEntity>();  

    Since our service methods heavily depend on the Get method, so none of the methods could be tested, but apart from this you can search for any other mocking framework that takes care of these situations.I guess this is a bug in mocking framework. Alternatively refrain yourself from using Get method with predicate (I would not suggest this approach as it is against the testing strategy.Our tests should not be limited to technical feasibility of methods). I got the following error while mocking repository,

    code

    “Invalid setup on a non-virtual (overridable in VB)”. I have commented out all UserServiceUnit test code, you can find it in available source code.

Test through NUnit UI

nunit

We have completed almost all the BusinessServices test, now let us try to execute these test on NUnit UI.

Step 1:

Launch NUnit UI. I have already explained how to install NUnit on the windows machine. Just launch the NUnit interface with its launch icon,

search

Step 2 :

Once the interface opens, click on File -> New Project and name the project as WebAPI.nunit and save it at any windows location.

window
nunit
webapi

Step 3:

Now, click on Project-> Add Assembly and browse for BusinessServices.Tests.dll (The library created for your unit test project when compiled)

project

add assembly

Step 4:

Once the assembly is browsed, you’ll see all the unit tests for that test project gets loaded in the UI and are visible on the interface.

token

Step 5:

At the right hand side panel of the interface, you’ll see a Run button that runs all the tests of business service. Just select the node BusinessServices in the tests tree on left side and press Run button on the right side.

buisness services

Once you run the tests, you’ll get green progress bar on right side and tick mark on all the tests on left side. That means all the tests are passed.In case any test fails, you’ll get cross mark on the test and red progress bar on right side.

run

But here, all of our tests are passed.

test

WebAPITests

Unit tests for WebAPI are not exactly like service methods, but vary in terms of testing HttpResponse, returned JSON, exception responses etc. Note that we’ll mock the classes and repository in a similar way in WebAPI unit tests as we did for services. One way of testing a web api is through web client and testing the actual endpoint or hosted URL of the service, but that is not considered as a unit test, that is called integration testing. In the next part of the article I’ll explain step by step procedure to unit test a web API. We’ll write tests for Product Controller.

Conclusion

In this article we learnt how to write unit tests for core business logic and primarily on basic CURD operations. The purpose was to get a basic idea on how unit tests are written and executed.You can add your own flavor to this that helps you in your real time project. My next article which explains unit tests for WebAPI controllers will be the continuation of this part.I hope this was useful to you. You can download the complete source code of this article with packages from GitHub. Happy coding.

Read more:

For more technical articles you can reach out to CodeTeddy

My other series of articles:

Read more articles on ASP.NET:

Up Next
    Ebook Download
    View all
    Learn
    View all