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

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

Published Sunday, December 9, 2012 3:11 AM by shiju
Filed under: , , ,

Comments

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

Tuesday, December 11, 2012 4:26 AM by türkiye bankalar

useful post, thank you. I need something like that.

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

Wednesday, December 12, 2012 6:54 AM by Grip

Personally, I prefer to inject something like an "IAjaxDetector" interface into my controller with a single method that returns a boolean (something like "IsAjaxRequest"). Then it's potentially easier to create a mock of that interface and have the real implementation just defer to Request.IsAjaxRequest; allows the tests to not have to touch the request/response in some scenarios and abstracts away the implementation (even though it's simple in this case).

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

Monday, December 17, 2012 10:18 AM by Todd

You are asserting the result is not null after using the result object, this should be your first assert. That is, you need to move the view name assert below the result is not null assert.

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

Monday, December 17, 2012 1:05 PM by Rollonz.com

Good Article.Trackback from Rollonz.com.

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

Tuesday, December 18, 2012 5:31 AM by Asp.Net Development

Thanks For sharing such a amazing post. Looking forward for such type of post. Good Going. Make sure you update this again soon.

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

Tuesday, April 30, 2013 3:13 AM by ASP.NET development

Some extremely valid points! I appreciate you writing this article plus the rest of the website is really good.

Leave a Comment

(required) 
(required) 
(optional)
(required)