Writing Unit Tests for an ASP.NET MVC Action Method that handles Ajax Request and Normal Request

Posted by shiju on ASP.net Weblogs See other posts from ASP.net Weblogs or by shiju
Published on Sun, 09 Dec 2012 08:11:41 GMT Indexed on 2012/12/09 11:10 UTC
Read the original article Hit count: 437

Filed under:
|
|
|

In this blog post, I will demonstrate how to write unit tests for an ASP.NET MVC action method, which handles both Ajax request and normal HTTP Request. I will write a unit test for specifying the behavior of an Ajax request and will write another unit test for specifying the behavior of a normal HTTP request. Both Ajax request and normal request will be handled by a single action method. So the ASP.NET MVC action method will be execute HTTP Request object’s IsAjaxRequest method for identifying whether it is an Ajax request or not. So we have to create mock object for Request object and also have to make as a Ajax request from the unit test for verifying the behavior of an Ajax request. I have used NUnit and Moq for writing unit tests.

Let me write a unit test for a Ajax request

Code Snippet
  1. [Test]
  2. public void Index_AjaxRequest_Returns_Partial_With_Expense_List()
  3. {
  4.     // Arrange  
  5.     Mock<HttpRequestBase> request = new Mock<HttpRequestBase>();
  6.     Mock<HttpResponseBase> response = new Mock<HttpResponseBase>();
  7.     Mock<HttpContextBase> context = new Mock<HttpContextBase>();
  8.  
  9.     context.Setup(c => c.Request).Returns(request.Object);
  10.     context.Setup(c => c.Response).Returns(response.Object);
  11.     //Add XMLHttpRequest request header
  12.     request.Setup(req => req["X-Requested-With"]).
  13.         Returns("XMLHttpRequest");
  14.  
  15.     IEnumerable<Expense> fakeExpenses = GetMockExpenses();
  16.     expenseRepository.Setup(x => x.GetMany(It.
  17.         IsAny<Expression<Func<Expense, bool>>>())).
  18.         Returns(fakeExpenses);
  19.     ExpenseController controller = new ExpenseController(
  20.         commandBus.Object, categoryRepository.Object,
  21.         expenseRepository.Object);
  22.     controller.ControllerContext = new ControllerContext(
  23.         context.Object, new RouteData(), controller);
  24.     // Act
  25.     var result = controller.Index(null, null) as PartialViewResult;
  26.     // Assert
  27.     Assert.AreEqual("_ExpenseList", result.ViewName);
  28.     Assert.IsNotNull(result, "View Result is null");
  29.     Assert.IsInstanceOf(typeof(IEnumerable<Expense>),
  30.             result.ViewData.Model, "Wrong View Model");
  31.     var expenses = result.ViewData.Model as IEnumerable<Expense>;
  32.     Assert.AreEqual(3, expenses.Count(),
  33.         "Got wrong number of Categories");        
  34. }

 

In the above unit test, we are calling Index action method of a controller named ExpenseController, which will returns a PartialView named _ExpenseList, if it is an Ajax request. We have created mock object for HTTPContextBase and setup XMLHttpRequest request header for Request object’s X-Requested-With for making it as a Ajax request. We have specified the ControllerContext property of the controller with mocked object HTTPContextBase.

Code Snippet
  1. controller.ControllerContext = new ControllerContext(
  2.         context.Object, new RouteData(), controller);

Let me write a unit test for a normal HTTP method

Code Snippet
  1. [Test]
  2. public void Index_NormalRequest_Returns_Index_With_Expense_List()
  3. {
  4.     // Arrange          
  5.     Mock<HttpRequestBase> request = new Mock<HttpRequestBase>();
  6.     Mock<HttpResponseBase> response = new Mock<HttpResponseBase>();
  7.     Mock<HttpContextBase> context = new Mock<HttpContextBase>();
  8.  
  9.     context.Setup(c => c.Request).Returns(request.Object);
  10.     context.Setup(c => c.Response).Returns(response.Object);
  11.  
  12.     IEnumerable<Expense> fakeExpenses = GetMockExpenses();
  13.  
  14.     expenseRepository.Setup(x => x.GetMany(It.
  15.         IsAny<Expression<Func<Expense, bool>>>())).
  16.         Returns(fakeExpenses);
  17.     ExpenseController controller = new ExpenseController(
  18.         commandBus.Object, categoryRepository.Object,
  19.         expenseRepository.Object);
  20.     controller.ControllerContext = new ControllerContext(
  21.         context.Object, new RouteData(), controller);
  22.     // Act
  23.     var result = controller.Index(null, null) as ViewResult;
  24.     // Assert
  25.     Assert.AreEqual("Index", result.ViewName);
  26.     Assert.IsNotNull(result, "View Result is null");
  27.     Assert.IsInstanceOf(typeof(IEnumerable<Expense>),
  28.             result.ViewData.Model, "Wrong View Model");
  29.     var expenses = result.ViewData.Model
  30.         as IEnumerable<Expense>;
  31.     Assert.AreEqual(3, expenses.Count(),
  32.         "Got wrong number of Categories");
  33. }

 

In the above unit test, we are not specifying the XMLHttpRequest request header for Request object’s X-Requested-With, so that it will be normal HTTP Request. If this is a normal request, the action method will return a ViewResult with a view template named Index.

The below is the implementation of Index action method

Code Snippet
  1. public ActionResult Index(DateTime? startDate, DateTime? endDate)
  2. {
  3.     //If date is not passed, take current month's first and last date
  4.     DateTime dtNow;
  5.     dtNow = DateTime.Today;
  6.     if (!startDate.HasValue)
  7.     {
  8.         startDate = new DateTime(dtNow.Year, dtNow.Month, 1);
  9.         endDate = startDate.Value.AddMonths(1).AddDays(-1);
  10.     }
  11.     //take last date of start date's month, if end date is not passed
  12.     if (startDate.HasValue && !endDate.HasValue)
  13.     {
  14.         endDate = (new DateTime(startDate.Value.Year,
  15.             startDate.Value.Month, 1)).AddMonths(1).AddDays(-1);
  16.     }
  17.     var expenses = expenseRepository.GetMany(
  18.         exp => exp.Date >= startDate && exp.Date <= endDate);
  19.     //if request is Ajax will return partial view
  20.     if (Request.IsAjaxRequest())
  21.     {
  22.         return PartialView("_ExpenseList", expenses);
  23.     }
  24.     //set start date and end date to ViewBag dictionary
  25.     ViewBag.StartDate = startDate.Value.ToShortDateString();
  26.     ViewBag.EndDate = endDate.Value.ToShortDateString();
  27.     //if request is not ajax
  28.     return View("Index",expenses);
  29. }

 

The index action method will returns a PartialView named _ExpenseList, if it is an Ajax request and will returns a View named Index if it is a normal request.

Source Code

The source code has been taken from my EFMVC app which can download from here

© ASP.net Weblogs or respective owner

Related posts about .NET

Related posts about ASP.NET