Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC unit test controller with HttpContext

I am trying to write a unit test for my one controller to verify if a view was returned properly, but this controller has a basecontroller that accesses the HttpContext.Current.Session. Everytime I create a new instance of my controller is calls the basecontroller constructor and the test fails with a null pointer exception on the HttpContext.Current.Session. Here is the code:

public class BaseController : Controller {            protected BaseController()     {        ViewData["UserID"] = HttpContext.Current.Session["UserID"];        } }  public class IndexController : BaseController {     public ActionResult Index()     {         return View("Index.aspx");     } }      [TestMethod]     public void Retrieve_IndexTest()     {         // Arrange         const string expectedViewName = "Index";          IndexController controller = new IndexController();          // Act         var result = controller.Index() as ViewResult;          // Assert         Assert.IsNotNull(result, "Should have returned a ViewResult");         Assert.AreEqual(expectedViewName, result.ViewName, "View name should have been {0}", expectedViewName);     } 

Any ideas on how to mock (using Moq) the Session that is accessed in the base controller so the test in the descendant controller will run?

like image 361
amurra Avatar asked Mar 23 '10 04:03

amurra


People also ask

How to mock HttpContext for controller?

Mock HTTPContext using DefaultHttpContext Please use the DefaultHttpContext object to set up a mock version of the HttpContext in the controller. var httpContext = new DefaultHttpContext(); Set up the custom header used 'X-Custom-Header', httpContext.

What is ControllerContext MVC?

ControllerContext(HttpContextBase, RouteData, ControllerBase) Initializes a new instance of the ControllerContext class by using the specified HTTP context, URL route data, and controller.


2 Answers

Unless you use Typemock or Moles, you can't.

In ASP.NET MVC you are not supposed to be using HttpContext.Current. Change your base class to use ControllerBase.ControllerContext - it has a HttpContext property that exposes the testable HttpContextBase class.

Here's an example of how you can use Moq to set up a Mock HttpContextBase:

var httpCtxStub = new Mock<HttpContextBase>();  var controllerCtx = new ControllerContext(); controllerCtx.HttpContext = httpCtxStub.Object;  sut.ControllerContext = controllerCtx;  // Exercise and verify the sut 

where sut represents the System Under Test (SUT), i.e. the Controller you wish to test.

like image 70
Mark Seemann Avatar answered Sep 19 '22 11:09

Mark Seemann


If you are using Typemock, you can do this:

Isolate.WhenCalled(()=>controller.HttpContext.Current.Session["UserID"]) .WillReturn("your id"); 

The test code will look like:

[TestMethod] public void Retrieve_IndexTest() {     // Arrange     const string expectedViewName = "Index";      IndexController controller = new IndexController();     Isolate.WhenCalled(()=>controller.HttpContext.Current.Session["UserID"])     .WillReturn("your id");     // Act     var result = controller.Index() as ViewResult;      // Assert     Assert.IsNotNull(result, "Should have returned a ViewResult");     Assert.AreEqual(expectedViewName, result.ViewName, "View name should have been {0}", expectedViewName); } 
like image 38
Graviton Avatar answered Sep 19 '22 11:09

Graviton