How to mock the Request on Controller in ASP.Net MVC?

94,362

Solution 1

Using Moq:

var request = new Mock<HttpRequestBase>();
// Not working - IsAjaxRequest() is static extension method and cannot be mocked
// request.Setup(x => x.IsAjaxRequest()).Returns(true /* or false */);
// use this
request.SetupGet(x => x.Headers).Returns(
    new System.Net.WebHeaderCollection {
        {"X-Requested-With", "XMLHttpRequest"}
    });

var context = new Mock<HttpContextBase>();
context.SetupGet(x => x.Request).Returns(request.Object);

var controller = new YourController();
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);

UPDATED:

Mock Request.Headers["X-Requested-With"] or Request["X-Requested-With"] instead of Request.IsAjaxRequest().

Solution 2

For anyone using NSubstitute I was able to modify the above answers and do something like this... (where Details is the Action method name on the controller)

 var fakeRequest = Substitute.For<HttpRequestBase>();
 var fakeContext = Substitute.For<HttpContextBase>();
 fakeRequest.Headers.Returns(new WebHeaderCollection { {"X-Requested-With", "XMLHttpRequest"}});
 fakeContext.Request.Returns(fakeRequest);
 controller.ControllerContext = new ControllerContext(fakeContext, new RouteData(), controller);
 var model = new EntityTypeMaintenanceModel();
        
 var result = controller.Details(model) as PartialViewResult;
        
 Assert.IsNotNull(result);
 Assert.AreEqual("EntityType", result.ViewName);

Solution 3

Here is a working solution using RhinoMocks. I've based it on a Moq solution I found at http://thegrayzone.co.uk/blog/2010/03/mocking-request-isajaxrequest/

public static void MakeAjaxRequest(this Controller controller)
{
        MockRepository mocks = new MockRepository();

        // Create mocks
        var mockedhttpContext = mocks.DynamicMock<HttpContextBase>();
        var mockedHttpRequest = mocks.DynamicMock<HttpRequestBase>();

        // Set headers to pretend it's an Ajax request
        SetupResult.For(mockedHttpRequest.Headers)
            .Return(new WebHeaderCollection() {
                {"X-Requested-With", "XMLHttpRequest"}
            });

        // Tell the mocked context to return the mocked request
        SetupResult.For(mockedhttpContext.Request).Return(mockedHttpRequest);

        mocks.ReplayAll();

        // Set controllerContext
        controller.ControllerContext = new ControllerContext(mockedhttpContext, new RouteData(), controller);
}

Solution 4

Is AjaxRequest is an extension method. So you can do it the following way using Rhino:

    protected HttpContextBase BuildHttpContextStub(bool isAjaxRequest)
    {
        var httpRequestBase = MockRepository.GenerateStub<HttpRequestBase>();   
        if (isAjaxRequest)
        {
            httpRequestBase.Stub(r => r["X-Requested-With"]).Return("XMLHttpRequest");
        }

        var httpContextBase = MockRepository.GenerateStub<HttpContextBase>();
        httpContextBase.Stub(c => c.Request).Return(httpRequestBase);

        return httpContextBase;
    }

    // Build controller
    ....
    controller.ControllerContext = new ControllerContext(BuildHttpContextStub(true), new RouteData(), controller);

Solution 5

Looks like you are looking for this,

 var requestMock = new Mock<HttpRequestBase>();
 requestMock.SetupGet(rq => rq["Age"]).Returns("2001");

Usage in Controller :

 public ActionResult Index()
 {
        var age = Request["Age"]; //This will return 2001
 }
Share:
94,362

Related videos on Youtube

Nissan
Author by

Nissan

Updated on May 17, 2021

Comments

  • Nissan
    Nissan about 3 years

    I have a controller in C# using the ASP.Net MVC framework

    public class HomeController:Controller{
      public ActionResult Index()
        {
          if (Request.IsAjaxRequest())
            { 
              //do some ajaxy stuff
            }
          return View("Index");
        }
    }
    

    I got some tips on mocking and was hoping to test the code with the following and RhinoMocks

    var mocks = new MockRepository();
    var mockedhttpContext = mocks.DynamicMock<HttpContextBase>();
    var mockedHttpRequest = mocks.DynamicMock<HttpRequestBase>();
    SetupResult.For(mockedhttpContext.Request).Return(mockedHttpRequest);
    
    var controller = new HomeController();
    controller.ControllerContext = new ControllerContext(mockedhttpContext, new RouteData(), controller);
    var result = controller.Index() as ViewResult;
    Assert.AreEqual("About", result.ViewName);
    

    However I keep getting this error:

    Exception System.ArgumentNullException: System.ArgumentNullException : Value cannot be null. Parameter name: request at System.Web.Mvc.AjaxRequestExtensions.IsAjaxRequest(HttpRequestBase request)

    Since the Request object on the controller has no setter. I tried to get this test working properly by using recommended code from an answer below.

    This used Moq instead of RhinoMocks, and in using Moq I use the following for the same test:

    var request = new Mock<HttpRequestBase>();
    // Not working - IsAjaxRequest() is static extension method and cannot be mocked
    // request.Setup(x => x.IsAjaxRequest()).Returns(true /* or false */);
    // use this
    request.SetupGet(x => x.Headers["X-Requested-With"]).Returns("XMLHttpRequest");
    
    var context = new Mock<HttpContextBase>();
    context.SetupGet(x => x.Request).Returns(request.Object);
    var controller = new HomeController(Repository, LoginInfoProvider);
    controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
    var result = controller.Index() as ViewResult;
    Assert.AreEqual("About", result.ViewName);
    

    but get the following error:

    Exception System.ArgumentException: System.ArgumentException : Invalid setup on a non-overridable member: x => x.Headers["X-Requested-With"] at Moq.Mock.ThrowIfCantOverride(Expression setup, MethodInfo methodInfo)

    Again, it seems like I cannot set the request header. How do I set this value, in RhinoMocks or Moq?

    • eu-ge-ne
      eu-ge-ne about 15 years
      Replace Request.IsAjaxRequest with Request.IsAjaxRequest()
    • eu-ge-ne
      eu-ge-ne about 15 years
      Mock Request.Headers["X-Requested-With"] or Request["X-Requested-With"] instead of Request.IsAjaxRequest(). I've updated my question
    • danfromisrael
      danfromisrael about 14 years
  • Nissan
    Nissan about 15 years
    and what would mockedHttpContext need to be mocked? tje RequestContext object it requires needs an HttpContextBase() object in the constructor, and HttpContextBase() has no constructor that accepts zero parameters.
  • Nissan
    Nissan about 15 years
    I get the message "The Type argument for method 'ISetupGetter<T, TProperty>Moq.Mock<T>.SetupGet<Tpropert>.... cannot be infered from uage. Try specifying the type arguments explicitly. What type do I set 'var request=' to though to get this to work?
  • eu-ge-ne
    eu-ge-ne about 15 years
    Just updated my answer - not Request.IsAjaxRequest but Request.IsAjaxRequest(). Update your question too
  • Nissan
    Nissan about 15 years
    I tried: var mocks = new MockRepository(); var mockedhttpContext = mocks.DynamicMock<HttpContextBase>(); var mockedHttpRequest = mocks.DynamicMock<HttpRequestBase>(); SetupResult.For(mockedhttpContext.Request).Return(mockedHttp‌​Request); var controller = new HomeController(Repository, LoginInfoProvider); controller.ControllerContext = new mockedhttpContext, new RouteData(), controller); var result = controller.Index() as ViewResult; However still get the same exception thrown.
  • Nissan
    Nissan about 15 years
    Still generates: Exception System.ArgumentException: System.ArgumentException : Invalid setup on a non-overridable member: x => x.IsAjaxRequest() at Moq.Mock.ThrowIfCantOverride(Expression setup, MethodInfo methodInfo)
  • eu-ge-ne
    eu-ge-ne about 15 years
    The problem is that IsAjaxRequest() is static extension method and cannot be mocked - I've updated my answer.
  • Nissan
    Nissan about 15 years
    should be context.SetupGet(x => x.Request).Returns(request.Object); your code above is missing the 's' on Return still Also results in Exception System.ArgumentException: System.ArgumentException : Invalid setup on a non-overridable member: x => x.Headers["X-Requested-With"] at Moq.Mock.ThrowIfCantOverride(Expression setup, MethodInfo methodInfo) error message
  • Damien
    Damien about 14 years
    Does anyone know how I can mock this when I need it to return false? I tried setting ["X-Requested-With"] to null or removing the mock all together but it fails
  • Vdex
    Vdex about 12 years
    Your link doesn't work, but the following seems to work _request.Setup(o => o.Form).Returns(new NameValueCollection());
  • Moojjoo
    Moojjoo about 9 years
    I am new to Moq, couple of questions: 1. where do you install Moq in your solution? (In other words do you only install in the TEST project) 2. Does Does Moq only come in C# or is there a VB.net Version?
  • LJNielsenDk
    LJNielsenDk almost 9 years
    @Moojjoo 1.: Just on the unit test project. 2.: I don't know. I seen anything about it but I also haven't been looking for it.
  • Emmanuel
    Emmanuel over 7 years
    A fantastic answer. BTW this solution is only if you want IsAjaxRequest() to return "true". The default behaviour is to return "false". So you don't need to do anything if you want to return "false"; no mocking and no header setting.
  • lastr2d2
    lastr2d2 over 2 years
    it works with Microsoft.AspNetCore.Mvc.Core 3.1 as well
  • Sasha Bond
    Sasha Bond about 2 years
    Alas, that HttpRequestBase is not in .net core 6.0