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.
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.
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
- namespace WebAPI.Controllers
- {
- using System.Linq;
- using System.Net;
- using System.Net.Http;
- using System.Web.Http;
- using WebAPI.Models;
- publicclassEmployeeController: ApiController
- {
- EntityModel context = newEntityModel();
- publicHttpResponseMessage Get(int id)
- {
- var employee = context.Employees.Where(p => p.Id == id)
- .FirstOrDefault();
- if (employee == null)
- {
- return Request.CreateResponse(HttpStatusCode.NotFound);
- }
- return Request.CreateResponse(HttpStatusCode.OK, employee);
- }
- ///<summary>
- /// Dispose
- ///</summary>
- ///<param name="disposing"></param>
- protectedoverridevoid Dispose(bool disposing)
- {
- context.Dispose();
- base.Dispose(disposing);
- }
- }
- }
- namespace WebAPI.Tests
- {
- using Microsoft.VisualStudio.TestTools.UnitTesting;
- using System.Net.Http;
- using System.Web.Http;
- using WebAPI.Controllers;
- using WebAPI.Models;
- [TestClass]
- publicclassEmployeeUnitTest
- {
- [TestMethod]
- publicvoid EmployeeGetById()
- {
- // Set up Prerequisites
- var controller = newEmployeeController();
- controller.Request = newHttpRequestMessage();
- controller.Configuration = newHttpConfiguration();
- // Act on Test
- var response = controller.Get(1);
- // Assert the result
- Employee employee;
- Assert.IsTrue(response.TryGetContentValue < Employee > (out employee));
- Assert.AreEqual("Jignesh", employee.Name);
- }
- }
- }
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
- namespace WebAPI.Controllers
- {
- using System.Linq;
- using System.Web.Http;
- using WebAPI.Models;
- publicclassDepartmentController: ApiController
- {
- EntityModel context = newEntityModel();
- publicIHttpActionResult Get(int id)
- {
- Department department = context.Departments.Where(p => p.DepartmentId == id)
- .FirstOrDefault();
- if (department == null)
- {
- return NotFound();
- }
- return Ok(department);
- }
- publicIHttpActionResult Post(Department department)
- {
- if (department != null)
- {
- context.Departments.Add(department);
- context.SaveChanges();
- return CreatedAtRoute("DefaultApi", new
- {
- id = department.DepartmentId
- }, department);
- }
- return BadRequest();
- }
- }
- }
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.
- namespace WebAPI.Tests
- {
- using Microsoft.VisualStudio.TestTools.UnitTesting;
- using System.Web.Http.Results;
- using WebAPI.Controllers;
- using WebAPI.Models;
- [TestClass]
- publicclassDepartmentUnitTest
- {
- [TestMethod]
- publicvoid DepartmentGetByIdSuccess()
- {
- // Set up Prerequisites
- var controller = newDepartmentController();
- // Act on Test
- var response = controller.Get(1);
- var contentResult = response asOkNegotiatedContentResult < Department > ;
- // Assert the result
- Assert.IsNotNull(contentResult);
- Assert.IsNotNull(contentResult.Content);
- Assert.AreEqual(1, contentResult.Content.DepartmentId);
- }
- }
- }
- [TestMethod]
- publicvoid GetDepartmentNotFound()
- {
- // Set up Prerequisites
- var controller = newDepartmentController();
- // Act
- IHttpActionResult actionResult = controller.Get(100);
- // Assert
- Assert.IsInstanceOfType(actionResult, typeof(NotFoundResult));
- }
- [TestMethod]
- publicvoid AddDepartmentTest()
- {
- // Arrange
- var controller = newDepartmentController();
- Department department = newDepartment
- {
- DepartmentName = "Test Department",
- };
- // Act
- IHttpActionResult actionResult = controller.Post(department);
- var createdResult = actionResult asCreatedAtRouteNegotiatedContentResult < Department > ;
- // Assert
- Assert.IsNotNull(createdResult);
- Assert.AreEqual("DefaultApi", createdResult.RouteName);
- Assert.IsNotNull(createdResult.RouteValues["id"]);
- }
Controller Method
- publicIHttpActionResult Put(Department department)
- {
- if (department != null)
- {
- // Do some work .
- return Content(HttpStatusCode.Accepted, department);
- }
- return BadRequest();
- }
- [TestMethod]
- publicvoid UpdateDepartmentTest()
- {
- // Arrange
- var controller = newDepartmentController();
- Department department = newDepartment
- {
- DepartmentId = 4,
- DepartmentName = "Test Department",
- };
- // Act
- IHttpActionResult actionResult = controller.Put(department);
- var contentResult = actionResult asNegotiatedContentResult < Department > ;
- Assert.IsNotNull(contentResult);
- Assert.AreEqual(HttpStatusCode.Accepted, contentResult.StatusCode);
- Assert.IsNotNull(contentResult.Content);
- }
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).
0 comments:
Post a Comment
Note: only a member of this blog may post a comment.