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. namespace mvcunittest.Models
  7. {
  8. public class EmpRepository : IEmployeeRepository
  9. {
  10. private vrEntities _db = new vrEntities();
  11. public IEnumerable<emp> GetAllEmployee()
  12. {
  13. return _db.emps.ToList();
  14. }
  15. public void CreateNewEmployee(emp employeeToCreate)
  16. {
  17. _db.emps.Add(employeeToCreate);
  18. _db.SaveChanges();
  19. }
  20. public void DeleteEmployee(int id)
  21. {
  22. var conToDel = GetEmployeeByID(id);
  23. _db.emps.Remove(conToDel);
  24. _db.SaveChanges();
  25. }
  26. public emp GetEmployeeByID(int id)
  27. {
  28. return _db.emps.FirstOrDefault(d => d.empno == id);
  29. }
  30. public int SaveChanges()
  31. {
  32. return _db.SaveChanges();
  33. }
  34. }
  35. public interface IEmployeeRepository
  36. {
  37. IEnumerable<emp> GetAllEmployee();
  38. void CreateNewEmployee(emp employeeToCreate);
  39. void DeleteEmployee(int id);
  40. emp GetEmployeeByID(int id);
  41. int SaveChanges();
  42. }
  43. }
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. public EmployeeController() : this(new EmpRepository()) { }
  13. public EmployeeController(IEmployeeRepository repository)
  14. {
  15. _repository = repository;
  16. }
  17. ////
  18. //// GET: /Employee/
  19. public ViewResult Index()
  20. {
  21. ViewData["ControllerName"] = this.ToString();
  22. return View("Index", _repository.GetAllEmployee());
  23. }
  24. ////
  25. //// GET: /Employee/Details/5
  26. public ActionResult Details(int id = 0)
  27. {
  28. //int idx = id.HasValue ? (int)id : 0;
  29. emp cnt = _repository.GetEmployeeByID(id);
  30. return View("Details", cnt);
  31. }
  32. //
  33. // GET: /Employee/Create
  34. public ActionResult Create()
  35. {
  36. return View("Create");
  37. }
  38. //
  39. // POST: /Employee/Create
  40. [HttpPost]
  41. public ActionResult Create([Bind(Exclude = "Id")] emp employeeToCreate)
  42. {
  43. try
  44. {
  45. if (ModelState.IsValid)
  46. {
  47. _repository.CreateNewEmployee(employeeToCreate);
  48. return RedirectToAction("Index");
  49. }
  50. }
  51. catch (Exception ex)
  52. {
  53. ModelState.AddModelError("", ex);
  54. ViewData["CreateError"] = "Unable to create; view innerexception";
  55. }
  56. return View("Create");
  57. }
  58. //
  59. // GET: /Employee/Edit/5
  60. public ActionResult Edit(int id = 0)
  61. {
  62. var employeeToEdit = _repository.GetEmployeeByID(id);
  63. return View(employeeToEdit);
  64. }
  65. //
  66. // GET: /Employee/Edit/5
  67. [HttpPost]
  68. public ActionResult Edit(int id, FormCollection collection)
  69. {
  70. emp cnt = _repository.GetEmployeeByID(id);
  71. try
  72. {
  73. if (TryUpdateModel(cnt))
  74. {
  75. _repository.SaveChanges();
  76. return RedirectToAction("Index");
  77. }
  78. }
  79. catch (Exception ex)
  80. {
  81. if (ex.InnerException != null)
  82. ViewData["EditError"] = ex.InnerException.ToString();
  83. else
  84. ViewData["EditError"] = ex.ToString();
  85. }
  86. #if DEBUG
  87. foreach (var modelState in ModelState.Values)
  88. {
  89. foreach (var error in modelState.Errors)
  90. {
  91. if (error.Exception != null)
  92. {
  93. throw modelState.Errors[0].Exception;
  94. }
  95. }
  96. }
  97. #endif
  98. return View(cnt);
  99. }
  100. //
  101. // GET: /Employee/Delete/5
  102. public ActionResult Delete(int id)
  103. {
  104. var conToDel = _repository.GetEmployeeByID(id);
  105. return View(conToDel);
  106. }
  107. //
  108. // POST: /Employee/Delete/5
  109. [HttpPost]
  110. public ActionResult Delete(int id, FormCollection collection)
  111. {
  112. try
  113. {
  114. _repository.DeleteEmployee(id);
  115. return RedirectToAction("Index");
  116. }
  117. catch
  118. {
  119. return View();
  120. }
  121. }
  122. }
  123. }
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. public Exception ExceptionToThrow { get; set; }
  13. public IEnumerable<emp> GetAllEmployee()
  14. {
  15. return _db.ToList();
  16. }
  17. public emp GetEmployeeByID(int id)
  18. {
  19. return _db.FirstOrDefault(d => d.empno == id);
  20. }
  21. public void CreateNewEmployee(emp employeeToCreate)
  22. {
  23. if (ExceptionToThrow != null)
  24. throw ExceptionToThrow;
  25. _db.Add(employeeToCreate);
  26. }
  27. public void SaveChanges(emp employeeToUpdate)
  28. {
  29. foreach (emp employee in _db)
  30. {
  31. if (employee.empno == employeeToUpdate.empno)
  32. {
  33. _db.Remove(employee);
  34. _db.Add(employeeToUpdate);
  35. break;
  36. }
  37. }
  38. }
  39. public void Add(emp employeeToAdd)
  40. {
  41. _db.Add(employeeToAdd);
  42. }
  43. public int SaveChanges()
  44. {
  45. return 1;
  46. }
  47. public void DeleteEmployee(int id)
  48. {
  49. _db.Remove(GetEmployeeByID(id));
  50. }
  51. }
  52. }
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. namespace mvcunittest.Tests.Controllers
  15. {
  16. [TestClass]
  17. public class EmployeeControllerTest
  18. {
  19. /// <summary>
  20. /// This method used for index view
  21. /// </summary>
  22. [TestMethod]
  23. public void IndexView()
  24. {
  25. var empcontroller = GetEmployeeController(new InmemoryEmpRepository());
  26. ViewResult result = empcontroller.Index();
  27. Assert.AreEqual("Index", result.ViewName);
  28. }
  29. /// <summary>
  30. /// This method used to get employee controller
  31. /// </summary>
  32. /// <param name="repository"></param>
  33. /// <returns></returns>
  34. private static EmployeeController GetEmployeeController(IEmployeeRepository emprepository)
  35. {
  36. EmployeeController empcontroller = new EmployeeController(emprepository);
  37. empcontroller.ControllerContext = new ControllerContext()
  38. {
  39. Controller = empcontroller,
  40. RequestContext = new RequestContext(new MockHttpContext(), new RouteData())
  41. };
  42. return empcontroller;
  43. }
  44. /// <summary>
  45. /// This method used to get all employye listing
  46. /// </summary>
  47. [TestMethod]
  48. public void GetAllEmployeeFromRepository()
  49. {
  50. // Arrange
  51. emp employee1 = GetEmployeeName(1, "ravi", 50000, 10);
  52. emp employee2 = GetEmployeeName(2, "suri", 50000, 10);
  53. InmemoryEmpRepository emprepository = new InmemoryEmpRepository();
  54. emprepository.Add(employee1);
  55. emprepository.Add(employee2);
  56. var controller = GetEmployeeController(emprepository);
  57. var result = controller.Index();
  58. var datamodel = (IEnumerable<emp>)result.ViewData.Model;
  59. CollectionAssert.Contains(datamodel.ToList(), employee1);
  60. CollectionAssert.Contains(datamodel.ToList(), employee2);
  61. }
  62. /// <summary>
  63. /// This method used to get emp name
  64. /// </summary>
  65. /// <param name="id"></param>
  66. /// <param name="lName"></param>
  67. /// <param name="fName"></param>
  68. /// <param name="title"></param>
  69. /// <param name="address"></param>
  70. /// <param name="city"></param>
  71. /// <param name="region"></param>
  72. /// <param name="postalCode"></param>
  73. /// <returns></returns>
  74. emp GetEmployeeName(int id, string lName, int s, int d)
  75. {
  76. return new emp
  77. {
  78. empno = id,
  79. ename = lName,
  80. sal = s,
  81. deptno = d
  82. };
  83. }
  84. /// <summary>
  85. /// This test method used to post employee
  86. /// </summary>
  87. [TestMethod]
  88. public void Create_PostEmployeeInRepository()
  89. {
  90. InmemoryEmpRepository emprepository = new InmemoryEmpRepository();
  91. EmployeeController empcontroller = GetEmployeeController(emprepository);
  92. emp employee = GetEmployeeID();
  93. empcontroller.Create(employee);
  94. IEnumerable<emp> employees = emprepository.GetAllEmployee();
  95. Assert.IsTrue(employees.Contains(employee));
  96. }
  97. /// <summary>
  98. ///
  99. /// </summary>
  100. /// <returns></returns>
  101. emp GetEmployeeID()
  102. {
  103. return GetEmployeeName(1, "ravi", 50000, 10);
  104. }
  105. /// <summary>
  106. ///
  107. /// </summary>
  108. [TestMethod]
  109. public void Create_PostRedirectOnSuccess()
  110. {
  111. EmployeeController controller = GetEmployeeController(new InmemoryEmpRepository());
  112. emp model = GetEmployeeID();
  113. var result = (RedirectToRouteResult)controller.Create(model);
  114. Assert.AreEqual("Index", result.RouteValues["action"]);
  115. }
  116. /// <summary>
  117. ///
  118. /// </summary>
  119. [TestMethod]
  120. public void ViewIsNotValid()
  121. {
  122. EmployeeController empcontroller = GetEmployeeController(new InmemoryEmpRepository());
  123. empcontroller.ModelState.AddModelError("", "mock error message");
  124. emp model = GetEmployeeName(1, "", 0, 0);
  125. var result = (ViewResult)empcontroller.Create(model);
  126. Assert.AreEqual("Create", result.ViewName);
  127. }
  128. /// <summary>
  129. ///
  130. /// </summary>
  131. [TestMethod]
  132. public void RepositoryThrowsException()
  133. {
  134. // Arrange
  135. InmemoryEmpRepository emprepository = new InmemoryEmpRepository();
  136. Exception exception = new Exception();
  137. emprepository.ExceptionToThrow = exception;
  138. EmployeeController controller = GetEmployeeController(emprepository);
  139. emp employee = GetEmployeeID();
  140. var result = (ViewResult)controller.Create(employee);
  141. Assert.AreEqual("Create", result.ViewName);
  142. ModelState modelState = result.ViewData.ModelState[""];
  143. Assert.IsNotNull(modelState);
  144. Assert.IsTrue(modelState.Errors.Any());
  145. Assert.AreEqual(exception, modelState.Errors[0].Exception);
  146. }
  147. private class MockHttpContext : HttpContextBase
  148. {
  149. private readonly IPrincipal _user = new GenericPrincipal(new GenericIdentity("someUser"), null /* roles */);
  150. public override IPrincipal User
  151. {
  152. get
  153. {
  154. return _user;
  155. }
  156. set
  157. {
  158. base.User = value;
  159. }
  160. }
  161. }
  162. }
  163. }
Now run the test cases:

test

After few seconds, we will see the following screen:

screen