Mocking ASP.NET MVC HttpConext and Sessions

Unit testing ASP.NET MVC controllers can be difficult when you start to use the HttpContext and Session state.  The following snippet of code will allow you to mock, using the Moq framework, the HttpContext properties.  Add this to your test project.

using System.Collections.Generic;
using System.Web;
using Moq;
using System.Collections.Specialized;
using System.Web.Routing;
using System.Web.Mvc;

namespace WebBackOffice.Tests
{
public class ContextMocks
{
public Mock<HttpContextBase> HttpContext { get; private set; }
public Mock<HttpRequestBase> Request { get; private set; }
public Mock<HttpResponseBase> Response { get; private set; }
public RouteData RouteData { get; private set; }

/// <summary>
/// Initializes a new instance of the <see cref="ContextMocks"/> class.
/// </summary>
/// <param name="controller">The controller to add mock context to.</param>
public ContextMocks(Controller controller)
{
// define all the common context objects, plus relationsips between them
HttpContext = new Mock<HttpContextBase>();
Request = new Mock<HttpRequestBase>();
Response = new Mock<HttpResponseBase>();
RouteData = new RouteData();

HttpContext.Setup(m => m.Request).Returns(Request.Object);
HttpContext.Setup(m => m.Response).Returns(Response.Object);
HttpContext.Setup(m => m.Session).Returns(new FakeSessionState());

Request.Setup(m => m.Cookies).Returns(new HttpCookieCollection());
Request.Setup(m => m.QueryString).Returns(new NameValueCollection());
Request.Setup(m => m.Form).Returns(new NameValueCollection());

Response.Setup(m => m.Cookies).Returns(new HttpCookieCollection());

// apply the mock context to the supplied controller instance
RequestContext rc = new RequestContext(HttpContext.Object, new RouteData());
controller.ControllerContext = new ControllerContext(rc, controller);
}

/// <summary>
/// Sets the ajax request header so that mocked HttpRequest shows as a ajax call.
/// </summary>
public void SetAjaxRequestHeader()
{
Request.Setup(f => f["X-Requested-With"])
.Returns("XMLHttpRequest");
}

private class FakeSessionState : HttpSessionStateBase
{
Dictionary<string, object> _items = new Dictionary<string, object>();

public override object this[string name]
{
get
{
return _items.ContainsKey(name) ? _items[name] : null;
}
set
{
_items[name] = value;
}
}
}
}
}

Below is an example of using this in a unit test, based on nunit test framework.  During the setup, create the ContextMock and associated with the controller under test.

namespace MySite.Tests
{
public class AccountControllerTests
{
private MyAccountController myAccountController;
private ContextMocks contextMock;
private Mock<IAccountService> accountServiceMock;

[SetUp]
public void Setup()
{
// create new controller under test
myAccountController = new MyAccountController();

// create mock HttpContext
contextMock = new ContextMocks(myAccountController);

accountServiceMock = new Mock<IAccountService>();
myAccountController.AccountService = accountServiceMock.Object;
}

[TearDown]
public void Cleanup()
{
myAccountController = null;
contextMock = null;
accountServiceMock = null;
}

[Test]
public void SignUp_AjaxRequest_Returns_JsonResult()
{
// arrange
string email = "test@test.com";
string password = "Some#rei!23";

// configure ajax mock request
contextMock.SetAjaxRequestHeader();

accountServiceMock.Setup(f => f.CreateAccount(It.IsAny<string>(), It.IsAny<string>()))
.Returns(new SignUpResponse(SignUpResponse.ReturnCodeType.Success));

// act
ActionResult actual = myAccountController.SignUp(email, password);

// assert
Assert.IsInstanceOf<JsonResult>(actual);
}
}
}

No comments: