Mocking Asp.net-mvc Context

Thus, the controller context depends on some internal elements of asp.net. What are some ways to cleanly expose them for unit tests? It seems very easy to hammer tests with tons of settings when I need, for example, Request.HttpMethod to return "GET".

I saw several examples / helpers on the networks, but some of them are dated. It is clear that this would be a good place to preserve the latest and greatest.

I am using the latest version of rhino mocks

+61
unit-testing asp.net-mvc moq mocking rhino-mocks
Aug 28 '08 at 15:50
source share
7 answers

Using MoQ looks something like this:

var request = new Mock<HttpRequestBase>(); request.Expect(r => r.HttpMethod).Returns("GET"); var mockHttpContext = new Mock<HttpContextBase>(); mockHttpContext.Expect(c => c.Request).Returns(request.Object); var controllerContext = new ControllerContext(mockHttpContext.Object , new RouteData(), new Mock<ControllerBase>().Object); 

I think the syntax of Rhino Mocks is similar.

+57
Aug 28 '08 at 16:06
source share

Here is an example of the unit test class using MsTest and Moq that mocks the HttpRequest and HttpResponse objects. (.NET 4.0, ASP.NET MVC 3.0)

The controller action receives the value from the request and sets the HTTP header in the response objects. Other http context objects can be mixed in the same way.

 [TestClass] public class MyControllerTest { protected Mock<HttpContextBase> HttpContextBaseMock; protected Mock<HttpRequestBase> HttpRequestMock; protected Mock<HttpResponseBase> HttpResponseMock; [TestInitialize] public void TestInitialize() { HttpContextBaseMock = new Mock<HttpContextBase>(); HttpRequestMock = new Mock<HttpRequestBase>(); HttpResponseMock = new Mock<HttpResponseBase>(); HttpContextBaseMock.SetupGet(x => x.Request).Returns(HttpRequestMock.Object); HttpContextBaseMock.SetupGet(x => x.Response).Returns(HttpResponseMock.Object); } protected MyController SetupController() { var routes = new RouteCollection(); var controller = new MyController(); controller.ControllerContext = new ControllerContext(HttpContextBaseMock.Object, new RouteData(), controller); controller.Url = new UrlHelper(new RequestContext(HttpContextBaseMock.Object, new RouteData()), routes); return controller; } [TestMethod] public void IndexTest() { HttpRequestMock.Setup(x => x["x"]).Returns("1"); HttpResponseMock.Setup(x => x.AddHeader("name", "value")); var controller = SetupController(); var result = controller.Index(); Assert.AreEqual("1", result.Content); HttpRequestMock.VerifyAll(); HttpResponseMock.VerifyAll(); } } public class MyController : Controller { public ContentResult Index() { var x = Request["x"]; Response.AddHeader("name", "value"); return Content(x); } } 
+19
Feb 22 '13 at 4:37
source share

Here is a snippet from Jason's link. Its just like Phil's method, but uses a rhino.

Note: mockHttpContext.Request is hatched to return mockRequest before . The internal mockRequest elements are crossed out. I believe this order is required.

 // create a fake web context var mockHttpContext = MockRepository.GenerateMock<HttpContextBase>(); var mockRequest = MockRepository.GenerateMock<HttpRequestBase>(); mockHttpContext.Stub(x => x.Request).Return(mockRequest); // tell the mock to return "GET" when HttpMethod is called mockRequest.Stub(x => x.HttpMethod).Return("GET"); var controller = new AccountController(); // assign the fake context var context = new ControllerContext(mockHttpContext, new RouteData(), controller); controller.ControllerContext = context; // act ... 
+17
Aug 29 '08 at 1:53
source share

The procedure for this seems to have changed a bit in MVC2 (I use RC1). Phil Haack's solution does not work for me if the action requires a specific method ( [HttpPost] , [HttpGet] ). Turning around Reflector, it looks like the method for checking these attributes has changed. MVC now checks request.Headers , request.Form and request.QueryString for the value of X-HTTP-Method-Override .

If you add mocks for these properties, it works:

 var request = new Mock<HttpRequestBase>(); request.Setup(r => r.HttpMethod).Returns("POST"); request.Setup(r => r.Headers).Returns(new NameValueCollection()); request.Setup(r => r.Form).Returns(new NameValueCollection()); request.Setup(r => r.QueryString).Returns(new NameValueCollection()); var mockHttpContext = new Mock<HttpContextBase>(); mockHttpContext.Expect(c => c.Request).Returns(request.Object); var controllerContext = new ControllerContext(mockHttpContext.Object, new RouteData(), new Mock<ControllerBase>().Object); 
+9
Dec 24 '09 at 17:15
source share

Or you can do this with Typemock Isolator without having to send a fake controller at all:

 Isolate.WhenCalled(()=>HttpContext.Request.HttpMethod).WillReturn("Get"); 
+7
Jan 29 '09 at 14:29
source share

I ended up with this specification

 public abstract class Specification <C> where C: Controller { protected C controller; HttpContextBase mockHttpContext; HttpRequestBase mockRequest; protected Exception ExceptionThrown { get; private set; } [SetUp] public void Setup() { mockHttpContext = MockRepository.GenerateMock<HttpContextBase>(); mockRequest = MockRepository.GenerateMock<HttpRequestBase>(); mockHttpContext.Stub(x => x.Request).Return(mockRequest); mockRequest.Stub(x => x.HttpMethod).Return("GET"); EstablishContext(); SetHttpContext(); try { When(); } catch (Exception exc) { ExceptionThrown = exc; } } protected void SetHttpContext() { var context = new ControllerContext(mockHttpContext, new RouteData(), controller); controller.ControllerContext = context; } protected T Mock<T>() where T: class { return MockRepository.GenerateMock<T>(); } protected abstract void EstablishContext(); protected abstract void When(); [TearDown] public virtual void TearDown() { } } 

and juice is here

 [TestFixture] public class When_invoking_ManageUsersControllers_Update :Specification <ManageUsersController> { private IUserRepository userRepository; FormCollection form; ActionResult result; User retUser; protected override void EstablishContext() { userRepository = Mock<IUserRepository>(); controller = new ManageUsersController(userRepository); retUser = new User(); userRepository.Expect(x => x.GetById(5)).Return(retUser); userRepository.Expect(x => x.Update(retUser)); form = new FormCollection(); form["IdUser"] = 5.ToString(); form["Name"] = 5.ToString(); form["Surename"] = 5.ToString(); form["Login"] = 5.ToString(); form["Password"] = 5.ToString(); } protected override void When() { result = controller.Edit(5, form); } [Test] public void is_retrieved_before_update_original_user() { userRepository.AssertWasCalled(x => x.GetById(5)); userRepository.AssertWasCalled(x => x.Update(retUser)); } } 

to use

+2
Oct. 20 '08 at 22:04
source share

I find the long mocking procedure is too much friction.

The best way we found - using ASP.NET MVC in a real project - is to abstract the HttpContext to an IWebContext interface that just goes through. Then you can mock IWebContext without pain.

Here is an example

+1
Aug 28 '08 at 23:01
source share



All Articles