Unit Testing In ASP.NET MVC

What is Unit Testing?

It is all about testing of every smallest testable block of a code in an automated manner.

Overview of the Repository Pattern

The Repository pattern is intended to create an abstraction layer between the data access layer and the business logic layer of an application. It is a data access pattern that prompts a more loosely coupled approach to data access. We create the data access logic in a separate class, or set of classes, called a repository, with the responsibility of persisting the application's business model.

As the Repository Pattern is useful for decoupling entity operations from presentation, it allows easy mocking and unit testing.

Getting Started

Create a new Project. Open Visual Studio 2012.

File - new - Project

Select Visual C#, then Web in installed templates.

Select ASP.NET MVC 4 Web Application.

Enter the Name and choose the location.
(here, I am giving the name as mvcunittest)

Click OK.

web

Click OK button.

In the next wizard there is a check box for creating a unit test project. For creating a unit test project select (check) that check box. We can add it later also or also add a new item feature.

Entity Data Model

Now, we can see the SolutionExplorer as given below:

SolutionExplorer

Now adding a new ADO.NET Entity Data Model and providing it a relevant name.

 ADO.NET Entity Data Model

 ADO.NET Entity Data Model

 ADO.NET Entity Data Model

Click Next and Click New Connection.

Here, I am selecting Microsoft SQL Server option.

Microsoft SQL Server

Click Continue,

Continue

Click Test Connection


Test Connection

Test Connection

From the tables list I am selecting emp table as given below:

tables

Click Finish
Finish

Now add a new class in Models:

Right click on Models folder - Add - class

Give the name as EmpRepository.cs

Now my code in EmpRepository.cs:

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Threading.Tasks;  
  6.   
  7. namespace mvcunittest.Models  
  8. {  
  9.     public class EmpRepository : IEmployeeRepository  
  10.     {  
  11.         private vrEntities _db = new vrEntities();  
  12.         public IEnumerable<emp> GetAllEmployee()  
  13.         {  
  14.             return _db.emps.ToList();  
  15.         }  
  16.   
  17.         public void CreateNewEmployee(emp employeeToCreate)  
  18.         {  
  19.             _db.emps.Add(employeeToCreate);  
  20.             _db.SaveChanges();  
  21.   
  22.         }  
  23.   
  24.         public void DeleteEmployee(int id)  
  25.         {  
  26.             var conToDel = GetEmployeeByID(id);  
  27.             _db.emps.Remove(conToDel);  
  28.             _db.SaveChanges();  
  29.   
  30.         }  
  31.   
  32.         public emp GetEmployeeByID(int id)  
  33.         {  
  34.             return _db.emps.FirstOrDefault(d => d.empno == id);  
  35.         }  
  36.   
  37.         public int SaveChanges()  
  38.         {  
  39.             return _db.SaveChanges();  
  40.         }  
  41.     }  
  42.   
  43.     public interface IEmployeeRepository  
  44.     {  
  45.         IEnumerable<emp> GetAllEmployee();  
  46.         void CreateNewEmployee(emp employeeToCreate);  
  47.         void DeleteEmployee(int id);  
  48.         emp GetEmployeeByID(int id);  
  49.         int SaveChanges();  
  50.     }  
  51.   
  52. }  
Now add a new controller in the Controllers folder.
(give the name as EmployeeController)

add

add

Code in EmployeeController.cs
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Web.Mvc;  
  6. using mvcunittest.Models;  
  7. namespace mvcunittest.Controllers  
  8. {  
  9.     public class EmployeeController : Controller  
  10.     {  
  11.         IEmployeeRepository _repository;  
  12.   
  13.         public EmployeeController() : this(new EmpRepository()) { }  
  14.   
  15.         public EmployeeController(IEmployeeRepository repository)  
  16.         {  
  17.             _repository = repository;  
  18.         }  
  19.   
  20.         ////  
  21.         //// GET: /Employee/  
  22.         public ViewResult Index()  
  23.         {  
  24.             ViewData["ControllerName"] = this.ToString();  
  25.             return View("Index", _repository.GetAllEmployee());  
  26.         }  
  27.   
  28.         ////  
  29.         //// GET: /Employee/Details/5  
  30.         public ActionResult Details(int id = 0)  
  31.         {  
  32.             //int idx = id.HasValue ? (int)id : 0;  
  33.             emp cnt = _repository.GetEmployeeByID(id);  
  34.             return View("Details", cnt);  
  35.         }  
  36.   
  37.         //  
  38.         // GET: /Employee/Create  
  39.   
  40.         public ActionResult Create()  
  41.         {  
  42.             return View("Create");  
  43.         }  
  44.   
  45.         //  
  46.         // POST: /Employee/Create  
  47.   
  48.         [HttpPost]  
  49.         public ActionResult Create([Bind(Exclude = "Id")] emp employeeToCreate)  
  50.         {  
  51.             try  
  52.             {  
  53.                 if (ModelState.IsValid)  
  54.                 {  
  55.                     _repository.CreateNewEmployee(employeeToCreate);  
  56.                     return RedirectToAction("Index");  
  57.                 }  
  58.             }  
  59.             catch (Exception ex)  
  60.             {  
  61.                 ModelState.AddModelError("", ex);  
  62.                 ViewData["CreateError"] = "Unable to create; view innerexception";  
  63.             }  
  64.   
  65.             return View("Create");  
  66.         }  
  67.   
  68.         //  
  69.         // GET: /Employee/Edit/5  
  70.         public ActionResult Edit(int id = 0)  
  71.         {  
  72.             var employeeToEdit = _repository.GetEmployeeByID(id);  
  73.             return View(employeeToEdit);  
  74.         }  
  75.   
  76.         //  
  77.         // GET: /Employee/Edit/5  
  78.         [HttpPost]  
  79.         public ActionResult Edit(int id, FormCollection collection)  
  80.         {  
  81.             emp cnt = _repository.GetEmployeeByID(id);  
  82.             try  
  83.             {  
  84.                 if (TryUpdateModel(cnt))  
  85.                 {  
  86.                     _repository.SaveChanges();  
  87.   
  88.                     return RedirectToAction("Index");  
  89.                 }  
  90.             }  
  91.             catch (Exception ex)  
  92.             {  
  93.                 if (ex.InnerException != null)  
  94.                     ViewData["EditError"] = ex.InnerException.ToString();  
  95.                 else  
  96.                     ViewData["EditError"] = ex.ToString();  
  97.             }  
  98. #if DEBUG  
  99.             foreach (var modelState in ModelState.Values)  
  100.             {  
  101.                 foreach (var error in modelState.Errors)  
  102.                 {  
  103.                     if (error.Exception != null)  
  104.                     {  
  105.                         throw modelState.Errors[0].Exception;  
  106.                     }  
  107.                 }  
  108.             }  
  109. #endif  
  110.             return View(cnt);  
  111.         }  
  112.   
  113.   
  114.         //  
  115.         // GET: /Employee/Delete/5  
  116.   
  117.         public ActionResult Delete(int id)  
  118.         {  
  119.             var conToDel = _repository.GetEmployeeByID(id);  
  120.             return View(conToDel);  
  121.         }  
  122.   
  123.         //  
  124.         // POST: /Employee/Delete/5  
  125.   
  126.         [HttpPost]  
  127.         public ActionResult Delete(int id, FormCollection collection)  
  128.         {  
  129.             try  
  130.             {  
  131.                 _repository.DeleteEmployee(id);  
  132.                 return RedirectToAction("Index");  
  133.             }  
  134.             catch  
  135.             {  
  136.                 return View();  
  137.             }  
  138.         }  
  139.   
  140.     }  
  141. }  
Now, build the project:

project

Now add View by right-clicking on Index action method in the controller and select strongly typed view and select model class which is created by a data model and select List from scaffold template and click Add.

Add

Add

You can add views in the same way for Create, Delete, Details. Edit scaffold templates.

After adding all the appropriate views, now go to Index.cshtml and we can see some code which is commented as given below,

code

Now, remove the comment make some changes as the following,

code

Similarly go to Details.cshtml, remove the comments and make the changes as given below,

Details

Now let's run the application to see the result.

result

We are now OK with the MVC application using a repository and the Entity Framework.

Now it is the time to work on Unit Testing. First of all create a models folder in the test project:

test

Give the folder name as Models.

Models

Models

Code in InmemoryEmpRepository.cs
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Threading.Tasks;  
  6. using mvcunittest.Models;  
  7. namespace mvcunittest.Tests.Models  
  8. {  
  9.     class InmemoryEmpRepository : IEmployeeRepository  
  10.     {  
  11.         private List<emp> _db = new List<emp>();  
  12.   
  13.         public Exception ExceptionToThrow { getset; }  
  14.   
  15.         public IEnumerable<emp> GetAllEmployee()  
  16.         {  
  17.             return _db.ToList();  
  18.         }  
  19.   
  20.         public emp GetEmployeeByID(int id)  
  21.         {  
  22.             return _db.FirstOrDefault(d => d.empno == id);  
  23.         }  
  24.   
  25.         public void CreateNewEmployee(emp employeeToCreate)  
  26.         {  
  27.             if (ExceptionToThrow != null)  
  28.                 throw ExceptionToThrow;  
  29.   
  30.             _db.Add(employeeToCreate);  
  31.         }  
  32.   
  33.         public void SaveChanges(emp employeeToUpdate)  
  34.         {  
  35.   
  36.             foreach (emp employee in _db)  
  37.             {  
  38.                 if (employee.empno == employeeToUpdate.empno)  
  39.                 {  
  40.                     _db.Remove(employee);  
  41.                     _db.Add(employeeToUpdate);  
  42.                     break;  
  43.                 }  
  44.             }  
  45.         }  
  46.   
  47.         public void Add(emp employeeToAdd)  
  48.         {  
  49.             _db.Add(employeeToAdd);  
  50.         }  
  51.   
  52.   
  53.         public int SaveChanges()  
  54.         {  
  55.             return 1;  
  56.         }  
  57.   
  58.         public void DeleteEmployee(int id)  
  59.         {  
  60.             _db.Remove(GetEmployeeByID(id));  
  61.         }  
  62.     }  
  63.   
  64. }  
add

add

Code in EmployeeControllerTest.cs:
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Threading.Tasks;  
  6. using mvcunittest.Controllers;  
  7. using mvcunittest.Models;  
  8. using mvcunittest.Tests.Models;  
  9. using Microsoft.VisualStudio.TestTools.UnitTesting;  
  10. using System.Web.Mvc;  
  11. using System.Web.Routing;  
  12. using System.Web;  
  13. using System.Security.Principal;  
  14.   
  15. namespace mvcunittest.Tests.Controllers  
  16. {  
  17.     [TestClass]  
  18.     public class EmployeeControllerTest  
  19.     {  
  20.         /// <summary>  
  21.         /// This method used for index view  
  22.         /// </summary>  
  23.         [TestMethod]  
  24.         public void IndexView()  
  25.         {  
  26.             var empcontroller = GetEmployeeController(new InmemoryEmpRepository());  
  27.             ViewResult result = empcontroller.Index();  
  28.             Assert.AreEqual("Index", result.ViewName);  
  29.         }  
  30.   
  31.   
  32.         /// <summary>  
  33.         /// This method used to get employee controller  
  34.         /// </summary>  
  35.         /// <param name="repository"></param>  
  36.         /// <returns></returns>  
  37.         private static EmployeeController GetEmployeeController(IEmployeeRepository emprepository)  
  38.         {  
  39.             EmployeeController empcontroller = new EmployeeController(emprepository);  
  40.             empcontroller.ControllerContext = new ControllerContext()  
  41.             {  
  42.                 Controller = empcontroller,  
  43.                 RequestContext = new RequestContext(new MockHttpContext(), new RouteData())  
  44.             };  
  45.             return empcontroller;  
  46.         }  
  47.   
  48.         /// <summary>  
  49.         ///  This method used to get all employye listing  
  50.         /// </summary>  
  51.         [TestMethod]  
  52.         public void GetAllEmployeeFromRepository()  
  53.         {  
  54.             // Arrange  
  55.             emp employee1 = GetEmployeeName(1, "ravi", 50000, 10);  
  56.             emp employee2 = GetEmployeeName(2, "suri", 50000, 10);  
  57.             InmemoryEmpRepository emprepository = new InmemoryEmpRepository();  
  58.             emprepository.Add(employee1);  
  59.             emprepository.Add(employee2);  
  60.             var controller = GetEmployeeController(emprepository);  
  61.             var result = controller.Index();  
  62.             var datamodel = (IEnumerable<emp>)result.ViewData.Model;  
  63.             CollectionAssert.Contains(datamodel.ToList(), employee1);  
  64.             CollectionAssert.Contains(datamodel.ToList(), employee2);  
  65.         }  
  66.   
  67.         /// <summary>  
  68.         /// This method used to get emp name  
  69.         /// </summary>  
  70.         /// <param name="id"></param>  
  71.         /// <param name="lName"></param>  
  72.         /// <param name="fName"></param>  
  73.         /// <param name="title"></param>  
  74.         /// <param name="address"></param>  
  75.         /// <param name="city"></param>  
  76.         /// <param name="region"></param>  
  77.         /// <param name="postalCode"></param>  
  78.         /// <returns></returns>  
  79.         emp GetEmployeeName(int id, string lName, int s, int d)  
  80.         {  
  81.             return new emp  
  82.             {  
  83.                 empno = id,  
  84.                 ename = lName,  
  85.                 sal = s,  
  86.                 deptno = d  
  87.   
  88.             };  
  89.         }  
  90.   
  91.         /// <summary>  
  92.         /// This test method used to post employee  
  93.         /// </summary>  
  94.         [TestMethod]  
  95.         public void Create_PostEmployeeInRepository()  
  96.         {  
  97.             InmemoryEmpRepository emprepository = new InmemoryEmpRepository();  
  98.             EmployeeController empcontroller = GetEmployeeController(emprepository);  
  99.             emp employee = GetEmployeeID();  
  100.             empcontroller.Create(employee);  
  101.             IEnumerable<emp> employees = emprepository.GetAllEmployee();  
  102.             Assert.IsTrue(employees.Contains(employee));  
  103.         }  
  104.   
  105.         /// <summary>  
  106.         ///  
  107.         /// </summary>  
  108.         /// <returns></returns>  
  109.         emp GetEmployeeID()  
  110.         {  
  111.             return GetEmployeeName(1, "ravi", 50000, 10);  
  112.         }  
  113.   
  114.         /// <summary>  
  115.         ///  
  116.         /// </summary>  
  117.         [TestMethod]  
  118.         public void Create_PostRedirectOnSuccess()  
  119.         {  
  120.             EmployeeController controller = GetEmployeeController(new InmemoryEmpRepository());  
  121.             emp model = GetEmployeeID();  
  122.             var result = (RedirectToRouteResult)controller.Create(model);  
  123.             Assert.AreEqual("Index", result.RouteValues["action"]);  
  124.         }  
  125.   
  126.         /// <summary>  
  127.         ///  
  128.         /// </summary>  
  129.         [TestMethod]  
  130.         public void ViewIsNotValid()  
  131.         {  
  132.             EmployeeController empcontroller = GetEmployeeController(new InmemoryEmpRepository());  
  133.             empcontroller.ModelState.AddModelError("""mock error message");  
  134.             emp model = GetEmployeeName(1, "", 0, 0);  
  135.             var result = (ViewResult)empcontroller.Create(model);  
  136.             Assert.AreEqual("Create", result.ViewName);  
  137.         }  
  138.   
  139.         /// <summary>  
  140.         ///  
  141.         /// </summary>  
  142.         [TestMethod]  
  143.         public void RepositoryThrowsException()  
  144.         {  
  145.             // Arrange  
  146.             InmemoryEmpRepository emprepository = new InmemoryEmpRepository();  
  147.             Exception exception = new Exception();  
  148.             emprepository.ExceptionToThrow = exception;  
  149.             EmployeeController controller = GetEmployeeController(emprepository);  
  150.             emp employee = GetEmployeeID();  
  151.             var result = (ViewResult)controller.Create(employee);  
  152.             Assert.AreEqual("Create", result.ViewName);  
  153.             ModelState modelState = result.ViewData.ModelState[""];  
  154.             Assert.IsNotNull(modelState);  
  155.             Assert.IsTrue(modelState.Errors.Any());  
  156.             Assert.AreEqual(exception, modelState.Errors[0].Exception);  
  157.         }  
  158.   
  159.         private class MockHttpContext : HttpContextBase  
  160.         {  
  161.             private readonly IPrincipal _user = new GenericPrincipal(new GenericIdentity("someUser"), null /* roles */);  
  162.   
  163.             public override IPrincipal User  
  164.             {  
  165.                 get  
  166.                 {  
  167.                     return _user;  
  168.                 }  
  169.                 set  
  170.                 {  
  171.                     base.User = value;  
  172.                 }  
  173.             }  
  174.         }  
  175.     }  
  176. }  
Now run the test cases:

test

After few seconds, we will see the following screen:

screen