Unit Testing Controllers In Web API

Introduction

TDD (Test-driven development) is a developmental approach in which TFD (Test-First Development) is there, and where we write a test before writing a code for the production. TDD is also supported by both MVC and Web API. In this article, we will learn how to write unit test case for Web API controller.

Following is a very common pattern in Unit Testing.

common pattern in Unit Testing

In the first step, we will have to create test data for testing, using a mock or stub object. This approach will minimize the number of dependencies.

Set up Unit test project

We have an option to create a Unit test project when we create a Web API project. When we create a unit test project with a web API project, Visual Studio IDE automatically adds Web API project reference to the unit test project.

web API project

Unit test project

Apart from this, we need to install the following packages to the Unit test project, because our unit test is dependent on these.

  • Microsoft.AspNet.WebApi
  • EntityFramework (if applicable)

If we want to inject any dependency to the controller, we can use the mock object. Using the following NuGet command, we can download a mock library.



Unit Test which returns HttpResponseMessage

In this following example, I have GET method in the controller and want to write a Unit test for this API method.

Controller Code

  1. namespace WebAPI.Controllers  
  2. {  
  3.     using System.Linq;  
  4.     using System.Net;  
  5.     using System.Net.Http;  
  6.     using System.Web.Http;  
  7.     using WebAPI.Models;  
  8.     publicclassEmployeeController: ApiController  
  9.     {  
  10.         EntityModel context = newEntityModel();  
  11.         publicHttpResponseMessage Get(int id)  
  12.         {  
  13.             var employee = context.Employees.Where(p => p.Id == id)  
  14.                 .FirstOrDefault();  
  15.             if (employee == null)  
  16.             {  
  17.                 return Request.CreateResponse(HttpStatusCode.NotFound);  
  18.             }  
  19.             return Request.CreateResponse(HttpStatusCode.OK, employee);  
  20.         }  
  21.         ///<summary>  
  22.         /// Dispose  
  23.         ///</summary>  
  24.         ///<param name="disposing"></param>  
  25.         protectedoverridevoid Dispose(bool disposing)  
  26.         {  
  27.             context.Dispose();  
  28.             base.Dispose(disposing);  
  29.         }  
  30.     }  
  31. }  
Unit Test
  1. namespace WebAPI.Tests  
  2. {  
  3.     using Microsoft.VisualStudio.TestTools.UnitTesting;  
  4.     using System.Net.Http;  
  5.     using System.Web.Http;  
  6.     using WebAPI.Controllers;  
  7.     using WebAPI.Models;  
  8.     [TestClass]  
  9.     publicclassEmployeeUnitTest  
  10.     {  
  11.         [TestMethod]  
  12.         publicvoid EmployeeGetById()  
  13.         {  
  14.             // Set up Prerequisites   
  15.             var controller = newEmployeeController();  
  16.             controller.Request = newHttpRequestMessage();  
  17.             controller.Configuration = newHttpConfiguration();  
  18.             // Act on Test  
  19.             var response = controller.Get(1);  
  20.             // Assert the result  
  21.             Employee employee;  
  22.             Assert.IsTrue(response.TryGetContentValue < Employee > (out employee));  
  23.             Assert.AreEqual("Jignesh", employee.Name);  
  24.         }  
  25.     }  
  26. }  
Here we set "Request" and "Configuration" on the controller. It is very important otherwise the Unit test will throw ArgumentNullException or InvalidOperationException.



Unit Test which returns IHttpActionResult

Web API also supports IHttpActionResult as a return type. This interface has a pre-defined command pattern to create HTTP responses. This approach is quite easy because IHttpActionResult creates the response. It is very easy to write a Unit test case with this approach because we can skip many things which are required for the setup HttpResponseMessage.

Example

In the following example, I created the controller called "DepartmentController" and GET method in the controller class. This method returns OK (department) when department is found in the database.

Controller Code
  1. namespace WebAPI.Controllers  
  2. {  
  3.     using System.Linq;  
  4.     using System.Web.Http;  
  5.     using WebAPI.Models;  
  6.     publicclassDepartmentController: ApiController  
  7.     {  
  8.         EntityModel context = newEntityModel();  
  9.         publicIHttpActionResult Get(int id)  
  10.         {  
  11.             Department department = context.Departments.Where(p => p.DepartmentId == id)  
  12.                 .FirstOrDefault();  
  13.             if (department == null)  
  14.             {  
  15.                 return NotFound();  
  16.             }  
  17.             return Ok(department);  
  18.         }  
  19.         publicIHttpActionResult Post(Department department)  
  20.         {  
  21.             if (department != null)  
  22.             {  
  23.                 context.Departments.Add(department);  
  24.                 context.SaveChanges();  
  25.                 return CreatedAtRoute("DefaultApi"new  
  26.                 {  
  27.                     id = department.DepartmentId  
  28.                 }, department);  
  29.             }  
  30.             return BadRequest();  
  31.         }  
  32.     }  
  33. }  
Unit Test

I have written the Unit test case, which returns 200 with the response body. In this Unit test, I have GET content result, using OkNegotiatedContentResult and I check whether the return object has the same departmentId.
  1. namespace WebAPI.Tests  
  2. {  
  3.     using Microsoft.VisualStudio.TestTools.UnitTesting;  
  4.     using System.Web.Http.Results;  
  5.     using WebAPI.Controllers;  
  6.     using WebAPI.Models;  
  7.     [TestClass]  
  8.     publicclassDepartmentUnitTest  
  9.     {  
  10.         [TestMethod]  
  11.         publicvoid DepartmentGetByIdSuccess()  
  12.         {  
  13.             // Set up Prerequisites   
  14.             var controller = newDepartmentController();  
  15.             // Act on Test  
  16.             var response = controller.Get(1);  
  17.             var contentResult = response asOkNegotiatedContentResult < Department > ;  
  18.             // Assert the result  
  19.             Assert.IsNotNull(contentResult);  
  20.             Assert.IsNotNull(contentResult.Content);  
  21.             Assert.AreEqual(1, contentResult.Content.DepartmentId);  
  22.         }  
  23.     }  
  24. }  
The following unit test is written to test the response of the action method, when the department is not found in the database.
  1. [TestMethod]  
  2. publicvoid GetDepartmentNotFound()  
  3. {  
  4.     // Set up Prerequisites   
  5.     var controller = newDepartmentController();  
  6.     // Act  
  7.     IHttpActionResult actionResult = controller.Get(100);  
  8.     // Assert  
  9.     Assert.IsInstanceOfType(actionResult, typeof(NotFoundResult));  
  10. }  
In the example given above, the Post method calls CreatedAtRoute for returning a Status code 201. In the following Unit test, I have verified that the action sets the correct routing value.
  1. [TestMethod]  
  2. publicvoid AddDepartmentTest()  
  3. {  
  4.     // Arrange  
  5.     var controller = newDepartmentController();  
  6.     Department department = newDepartment  
  7.     {  
  8.         DepartmentName = "Test Department",  
  9.     };  
  10.     // Act  
  11.     IHttpActionResult actionResult = controller.Post(department);  
  12.     var createdResult = actionResult asCreatedAtRouteNegotiatedContentResult < Department > ;  
  13.     // Assert  
  14.     Assert.IsNotNull(createdResult);  
  15.     Assert.AreEqual("DefaultApi", createdResult.RouteName);  
  16.     Assert.IsNotNull(createdResult.RouteValues["id"]);  
  17. }  
We can also verify the status code of the action methods.
 
For example, Put method return status is code 202 (Accepted), OK (200) etc.
 

Controller Method
  1. publicIHttpActionResult Put(Department department)  
  2. {  
  3.     if (department != null)  
  4.     {  
  5.         // Do some work .  
  6.         return Content(HttpStatusCode.Accepted, department);  
  7.     }  
  8.     return BadRequest();  
  9. }  
Unit test
  1. [TestMethod]  
  2. publicvoid UpdateDepartmentTest()  
  3. {  
  4.     // Arrange  
  5.     var controller = newDepartmentController();  
  6.     Department department = newDepartment  
  7.     {  
  8.         DepartmentId = 4,  
  9.             DepartmentName = "Test Department",  
  10.     };  
  11.     // Act  
  12.     IHttpActionResult actionResult = controller.Put(department);  
  13.     var contentResult = actionResult asNegotiatedContentResult < Department > ;  
  14.     Assert.IsNotNull(contentResult);  
  15.     Assert.AreEqual(HttpStatusCode.Accepted, contentResult.StatusCode);  
  16.     Assert.IsNotNull(contentResult.Content);  
  17. }  
Summary

Unit test is a code that helps us in verifying the expected behavior of the other code in isolation. Here “In isolation" means there is no dependency between the tests. This is a better idea to test the Application code, before it goes for quality assurance (QA).