Unit Testing In MVC Projects

Here in this article I will explain what Unit Testing is in MVC projects. When MVC was launched Unit Testing was promoted as one of the biggest advantages of using MVC when developing business applications. If your business application is growing day by day then it becomes challenging to keep the application on track. Then Unit Testing plays a vital role in the success of your business application.

Now we will learn Unit Testing step-by-step. Here I will create a MVC application first with Entity Framework to do CRUD operations.

Open Visual Studio 2012 -> New -> Project.





Now your solution will look as in the following.



Now right-click on the Model Folder then select Add -> ADO.NET Entity Data Model.















Here we will use the repository pattern so right-click on the Model Folder then select Add New Interface.



Define the following method in IEmployeeRepository.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 UnitTestingAppInMVC.Models  
  8. {  
  9.    public interface IEmployeeRepository : IDisposable  
  10.    {  
  11.       IEnumerable<Employee> GetAllEmployee();  
  12.       Employee GetEmployeeByID(int emp_ID);  
  13.       void InsertEmployee(Employee emp);  
  14.       void DeleteEmployee(int emp_ID);  
  15.       void UpdateEmployee(Employee emp);  
  16.       int Save();  
  17.    }  
  18. }  
Now again right-click on the Model Folder then select Add New Class.



EmployeeRepository.cs is
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Data;  
  4. using System.Linq;  
  5. using System.Web;  
  6.   
  7. namespace UnitTestingAppInMVC.Models   
  8. {  
  9.     public class EmployeeRepository: IEmployeeRepository,  
  10.     IDisposable   
  11.     {  
  12.   
  13.         EmployeeManagementEntities context = new EmployeeManagementEntities();  
  14.   
  15.         public IEnumerable < Employee > GetAllEmployee()   
  16.         {  
  17.             return context.Employee.ToList();  
  18.         }  
  19.   
  20.         public Employee GetEmployeeByID(int id)   
  21.         {  
  22.             return context.Employee.Find(id);  
  23.         }  
  24.   
  25.         public void InsertEmployee(Employee emp)   
  26.         {  
  27.             context.Employee.Add(emp);  
  28.         }  
  29.   
  30.         public void DeleteEmployee(int emp_ID)   
  31.         {  
  32.             Employee emp = context.Employee.Find(emp_ID);  
  33.             context.Employee.Remove(emp);  
  34.         }  
  35.   
  36.         public void UpdateEmployee(Employee emp)   
  37.         {  
  38.             context.Entry(emp).State = EntityState.Modified;  
  39.         }  
  40.   
  41.         public int Save()   
  42.         {  
  43.             return context.SaveChanges();  
  44.         }  
  45.   
  46.         private bool disposed = false;  
  47.   
  48.         protected virtual void Dispose(bool disposing)   
  49.         {  
  50.             if (!this.disposed)  
  51.             {  
  52.                 if (disposing)   
  53.                 {  
  54.                     context.Dispose();  
  55.                 }  
  56.             }  
  57.             this.disposed = true;  
  58.         }  
  59.   
  60.         public void Dispose()   
  61.         {  
  62.             Dispose(true);  
  63.             GC.SuppressFinalize(this);  
  64.         }  
  65.     }  
  66. }  
Now Right-click on the Controller then select Add New Controller.


  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Web.Mvc;  
  6. using UnitTestingAppInMVC.Models;  
  7. using PagedList;  
  8. using System.Data;  
  9.   
  10. namespace UnitTestingAppInMVC.Controllers  
  11. {  
  12.     public class EmployeeController: Controller   
  13.     {  
  14.         IEmployeeRepository employeeRepository;  
  15.   
  16.         public EmployeeController(): this(new EmployeeRepository()) {}  
  17.   
  18.         public EmployeeController(IEmployeeRepository repository)  
  19.         {  
  20.             employeeRepository = repository;  
  21.         }  
  22.   
  23.         public ViewResult Index(string sortOrder, string currentFilter, string searchString, int ? page)   
  24.         {  
  25.             ViewData["ControllerName"] = this.ToString();  
  26.             ViewBag.CurrentSort = sortOrder;  
  27.             ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Emp_ID" : "";  
  28.   
  29.             if (searchString != null)   
  30.             {  
  31.                 page = 1;  
  32.             } else {  
  33.                 searchString = currentFilter;  
  34.             }  
  35.             ViewBag.CurrentFilter = searchString;  
  36.   
  37.             var employees = from s in employeeRepository.GetAllEmployee()  
  38.             select s;  
  39.             if (!String.IsNullOrEmpty(searchString))  
  40.             {  
  41.                 employees = employees.Where(s = > s.Name.ToUpper().Contains(searchString.ToUpper()) || s.Name.ToUpper().Contains(searchString.ToUpper()));  
  42.             }  
  43.             switch (sortOrder) {  
  44.                 case "Emp ID":  
  45.                     employees = employees.OrderByDescending(s = > s.Emp_ID);  
  46.                     break;  
  47.                 case "Name":  
  48.                     employees = employees.OrderBy(s = > s.Name);  
  49.                     break;  
  50.                 case "State":  
  51.                     employees = employees.OrderByDescending(s = > s.State);  
  52.                     break;  
  53.                 case "Country":  
  54.                     employees = employees.OrderByDescending(s = > s.Country);  
  55.                     break;  
  56.                 default:  
  57.                     employees = employees.OrderBy(s = > s.Emp_ID);  
  58.                     break;  
  59.             }  
  60.   
  61.             int pageSize = 5;  
  62.             int pageNumber = (page ? ? 1);  
  63.             return View("Index", employees.ToPagedList(pageNumber, pageSize));  
  64.         }  
  65.   
  66.         //    
  67.         // GET: /Employee/Details/5    
  68.   
  69.         public ViewResult Details(int id)   
  70.         {  
  71.             Employee emp = employeeRepository.GetEmployeeByID(id);  
  72.             return View(emp);  
  73.         }  
  74.   
  75.         //    
  76.         // GET: /Employee/Create    
  77.   
  78.         public ActionResult Create()  
  79.         {  
  80.             return View("Create");  
  81.         }  
  82.   
  83.         //    
  84.         // POST: /Employee/Create    
  85.   
  86.         [HttpPost]  
  87.         public ActionResult Create(Employee emp)   
  88.         {  
  89.             try {  
  90.                 if (ModelState.IsValid)   
  91.                 {  
  92.                     employeeRepository.InsertEmployee(emp);  
  93.                     employeeRepository.Save();  
  94.                     return RedirectToAction("Index");  
  95.                 }  
  96.             }   
  97.             catch (Exception ex)   
  98.             {  
  99.                 ModelState.AddModelError(string.Empty, "Some Error Occured.");  
  100.             }  
  101.             return View("Create", emp);  
  102.         }  
  103.   
  104.         //    
  105.         // GET: /Employee/Edit/5    
  106.   
  107.         public ActionResult Edit(int id)   
  108.         {  
  109.             Employee emp = employeeRepository.GetEmployeeByID(id);  
  110.             return View(emp);  
  111.         }  
  112.   
  113.         //    
  114.         // POST: /Employee/Edit/5    
  115.   
  116.         [HttpPost]  
  117.         [ValidateAntiForgeryToken]  
  118.         public ActionResult Edit(Employee emp)   
  119.         {  
  120.             try   
  121.             {  
  122.                 if (ModelState.IsValid)   
  123.                 {  
  124.                     employeeRepository.UpdateEmployee(emp);  
  125.                     employeeRepository.Save();  
  126.                     return RedirectToAction("Index");  
  127.                 }  
  128.             }   
  129.             catch (Exception ex)   
  130.             {  
  131.                 ModelState.AddModelError(string.Empty, "Some error Occured.");  
  132.             }  
  133.             return View(emp);  
  134.         }  
  135.   
  136.         //    
  137.         // GET: /employee/Delete/5    
  138.   
  139.         public ActionResult Delete(bool ? saveChangesError = falseint id = 0)   
  140.         {  
  141.             if (saveChangesError.GetValueOrDefault())   
  142.             {  
  143.                 ViewBag.ErrorMessage = "Some Error Occured.";  
  144.             }  
  145.             Employee emp = employeeRepository.GetEmployeeByID(id);  
  146.             return View(emp);  
  147.         }  
  148.   
  149.         //    
  150.         // POST: /Employee/Delete/5    
  151.   
  152.         [HttpPost]  
  153.         [ValidateAntiForgeryToken]  
  154.         public ActionResult Delete(int id)  
  155.         {  
  156.             try  
  157.             {  
  158.                 Employee emp = employeeRepository.GetEmployeeByID(id);  
  159.                 employeeRepository.DeleteEmployee(id);  
  160.                 employeeRepository.Save();  
  161.             }   
  162.             catch (Exception ex)   
  163.             {  
  164.                 return RedirectToAction("Delete"new  
  165.                 {  
  166.                     id = id, saveChangesError = true  
  167.                 });  
  168.             }  
  169.             return RedirectToAction("Index");  
  170.         }  
  171.   
  172.         protected override void Dispose(bool disposing)  
  173.         {  
  174.             employeeRepository.Dispose();  
  175.             base.Dispose(disposing);  
  176.         }  
  177.   
  178.     }  
  179. }  
Now add a View for the Index, Detail, Edit and Delete Action methods.


Unit Testing

Now to work on the Unit Testing part.

In UnitTestingAppInMVC.Tests add a folder named Model. Right-click on the Model Folder then select Add New Class InMemoryEmployeeRepository.cs.

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Threading.Tasks;  
  6. using UnitTestingAppInMVC.Models;  
  7.   
  8. namespace UnitTestingAppInMVC.Tests.Models   
  9. {  
  10.     class InMemoryEmployeeRepository: IEmployeeRepository   
  11.     {  
  12.         private List < Employee > _db = new List < Employee > ();  
  13.   
  14.         public Exception ExceptionToThrow  
  15.         {  
  16.             get;  
  17.             set;  
  18.         }  
  19.   
  20.         public IEnumerable < Employee > GetAllEmployee()   
  21.         {  
  22.             return _db.ToList();  
  23.         }  
  24.   
  25.         public Employee GetEmployeeByID(int id)  
  26.         {  
  27.             return _db.FirstOrDefault(d = > d.Emp_ID == id);  
  28.         }  
  29.   
  30.         public void InsertEmployee(Employee employeeToCreate)  
  31.         {  
  32.   
  33.   
  34.             _db.Add(employeeToCreate);  
  35.         }  
  36.   
  37.         public void DeleteEmployee(int id)  
  38.         {  
  39.             _db.Remove(GetEmployeeByID(id));  
  40.         }  
  41.   
  42.   
  43.         public void UpdateEmployee(Employee employeeToUpdate)  
  44.         {  
  45.   
  46.             foreach(Employee employee in _db)  
  47.             {  
  48.                 if (employee.Emp_ID == employeeToUpdate.Emp_ID)   
  49.                 {  
  50.                     _db.Remove(employee);  
  51.                     _db.Add(employeeToUpdate);  
  52.                     break;  
  53.                 }  
  54.             }  
  55.         }  
  56.   
  57.         public int Save()   
  58.         {  
  59.             return 1;  
  60.         }  
  61.   
  62.   
  63.         private bool disposed = false;  
  64.   
  65.         protected virtual void Dispose(bool disposing)  
  66.         {  
  67.             if (!this.disposed)   
  68.             {  
  69.                 if (disposing)   
  70.                 {  
  71.                     //Dispose Object Here    
  72.                 }  
  73.             }  
  74.             this.disposed = true;  
  75.         }  
  76.   
  77.         public void Dispose()   
  78.         {  
  79.             Dispose(true);  
  80.             GC.SuppressFinalize(this);  
  81.         }  
  82.     }  
  83. }  

Add A New Controller class

Now add a new Controller class EmployeeControllerTest.cs.

Here define all your action methods as Test Methods for which you want to do Unit Testing.
  1. using Microsoft.VisualStudio.TestTools.UnitTesting;  
  2. using System;  
  3. using System.Collections.Generic;  
  4. using System.Linq;  
  5. using System.Security.Principal;  
  6. using System.Text;  
  7. using System.Threading.Tasks;  
  8. using System.Web;  
  9. using System.Web.Mvc;  
  10. using System.Web.Routing;  
  11. using UnitTestingAppInMVC.Controllers;  
  12. using UnitTestingAppInMVC.Models;  
  13. using UnitTestingAppInMVC.Tests.Models;  
  14.   
  15. namespace UnitTestingAppInMVC.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 InMemoryEmployeeRepository());  
  27.   
  28.             ViewResult result = empcontroller.Index(nullnullnullnull);  
  29.             Assert.AreEqual("Index", result.ViewName);  
  30.             Assert.IsInstanceOfType(result, typeof(ViewResult));  
  31.         }  
  32.   
  33.         /// <summary>    
  34.         /// This method used to get employee controller    
  35.         /// </summary>    
  36.         /// <param name="repository"></param>    
  37.         /// <returns></returns>    
  38.         private static EmployeeController GetEmployeeController(IEmployeeRepository emprepository)   
  39.         {  
  40.             EmployeeController empcontroller = new EmployeeController(emprepository);  
  41.             empcontroller.ControllerContext = new ControllerContext()   
  42.             {  
  43.                 Controller = empcontroller,  
  44.                 RequestContext = new RequestContext(new MockHttpContext(), new RouteData())  
  45.             };  
  46.             return empcontroller;  
  47.         }  
  48.   
  49.         /// <summary>    
  50.         /// This method used to get all employye listing    
  51.         /// </summary>    
  52.         [TestMethod]  
  53.         public void GetAllEmployeeFromRepository()   
  54.         {  
  55.             // Arrange    
  56.             Employee employee1 = GetEmployeeName(1, "Rahul Saxena""[email protected]""Software Developer""Noida""Uttar Pradesh""India");  
  57.             Employee employee2 = GetEmployeeName(2, "Abhishek Saxena""[email protected]""Tester""Saharanpur""Uttar Pradesh""India");  
  58.             InMemoryEmployeeRepository emprepository = new InMemoryEmployeeRepository();  
  59.             emprepository.InsertEmployee(employee1);  
  60.             emprepository.InsertEmployee(employee2);  
  61.             var controller = GetEmployeeController(emprepository);  
  62.             var result = controller.Index(nullnullnullnull);  
  63.             var datamodel = (IEnumerable < Employee > ) result.ViewData.Model;  
  64.             CollectionAssert.Contains(datamodel.ToList(), employee1);  
  65.             CollectionAssert.Contains(datamodel.ToList(), employee2);  
  66.         }  
  67.   
  68.         /// <summary>    
  69.         /// This method used to get emp name    
  70.         /// </summary>    
  71.         /// <param name="Emp_ID"></param>    
  72.         /// <param name="Name"></param>    
  73.         /// <param name="Email"></param>    
  74.         /// <param name="Designation"></param>    
  75.         /// <param name="City"></param>    
  76.         /// <param name="State"></param>    
  77.         /// <param name="Country"></param>     
  78.         /// <returns></returns>    
  79.         Employee GetEmployeeName(int Emp_ID, string Name, string Email, string Designation, string City, string State, string Country)   
  80.         {  
  81.             return new Employee   
  82.             {  
  83.                 Emp_ID = Emp_ID,  
  84.                 Name = Name,  
  85.                 Email = Email,  
  86.                 Designation = Designation,  
  87.                 City = City,  
  88.                 State = State,  
  89.                 Country = Country  
  90.             };  
  91.         }  
  92.   
  93.         /// <summary>    
  94.         /// This test method used to post employee    
  95.         /// </summary>    
  96.   
  97.         [TestMethod]  
  98.         public void Create_PostEmployeeInRepository()  
  99.         {  
  100.             InMemoryEmployeeRepository emprepository = new InMemoryEmployeeRepository();  
  101.             EmployeeController empcontroller = GetEmployeeController(emprepository);  
  102.             Employee employee = GetEmployeeID();  
  103.             empcontroller.Create(employee);  
  104.             IEnumerable < Employee > employees = emprepository.GetAllEmployee();  
  105.             Assert.IsTrue(employees.Contains(employee));  
  106.         }  
  107.   
  108.         /// <summary>    
  109.         ///    
  110.         /// </summary>    
  111.         /// <returns></returns>    
  112.         Employee GetEmployeeID()   
  113.         {  
  114.             return GetEmployeeName(1, "Rahul Saxena""[email protected]""Software Developer""Noida""Uttar Pradesh""India");  
  115.         }  
  116.   
  117.         /// <summary>    
  118.         ///    
  119.         /// </summary>    
  120.         [TestMethod]  
  121.         public void Create_PostRedirectOnSuccess()  
  122.         {  
  123.             EmployeeController controller = GetEmployeeController(new InMemoryEmployeeRepository());  
  124.             Employee model = GetEmployeeID();  
  125.             var result = (RedirectToRouteResult) controller.Create(model);  
  126.             Assert.AreEqual("Index", result.RouteValues["action"]);  
  127.         }  
  128.   
  129.         /// <summary>    
  130.         ///    
  131.         /// </summary>    
  132.         [TestMethod]  
  133.         public void ViewIsNotValid()   
  134.         {  
  135.             EmployeeController empcontroller = GetEmployeeController(new InMemoryEmployeeRepository());  
  136.             empcontroller.ModelState.AddModelError("""mock error message");  
  137.             Employee model = GetEmployeeName(1, """""""""""");  
  138.             var result = (ViewResult) empcontroller.Create(model);  
  139.             Assert.AreEqual("Create", result.ViewName);  
  140.         }  
  141.     }  
  142.   
  143.     public class MockHttpContext: HttpContextBase  
  144.     {  
  145.         private readonly IPrincipal _user = new GenericPrincipal(new GenericIdentity("someUser"), null /* roles */ );  
  146.   
  147.         public override IPrincipal User  
  148.         {  
  149.             get   
  150.             {  
  151.                 return _user;  
  152.             }  
  153.             set   
  154.             {  
  155.                 base.User = value;  
  156.             }  
  157.         }  
  158.     }  
  159. }  
Now run your test methods.





See your Test Run result here.


Similar Articles