views:

81

answers:

2

I am trying to mock the Ajax.IsRequest() method of ASP.Net MVC. I found out how to do it in order for it to return true:

Expect.Call(_myController.Request.Headers["X-Requested-With"]).Return("XMLHttpRequest").Repeat.Any();

This works and returns true. Now I need to test the other branch of the code. How can I mock it to return false? I have tried removing the mock altogether, It fails with:

System.NullReferenceException : Object reference not set to an instance of an object.]

If I do:

Expect.Call(_templateReportController.Request["X-Requested-With"]).Return(null).Repeat.Any();

It fails with the same error.

Entire Test:

  /// <summary>
    /// Tests the Edit Action when calling via Ajax
    /// </summary>
    [Test]
    public void Test_Edit_AjaxRequest()
    {
        Group group = new Group();
        group.ID = 1;
        group.Name = "Admin";
        IList<Group> groupList = new List<Group>() { group };

        Definition def  = new Definition();
        def.ID = 1;
        def.Name = "Report";
        def.LastModified = DateTime.UtcNow;
        def.Groups.Add(group);


        using (_mocks.Record())
        {
            Expect.Call(_myController.Request["X-Requested-With"]).Return("XMLHttpRequest").Repeat.Any();
            Expect.Call(_DefBiz.GetAll<Group>()).Return(groupList);
            Expect.Call(_DefBiz.Get<Definition>(1)).Return(def);
        }

        myController.DefAccess = _DefBiz;
        PartialViewResult actual;

        using (_mocks.Playback())
        {
            actual = (PartialViewResult)myController.Edit(1);
        }


    }

Any advices? Cheers

A: 
Expect.Call(_myController.Request.Headers["X-Requested-With"]).Return("SpitAndDuctTape").Repeat.Any();

...should do the job.

Craig Stuntz
Fails as Request.Headers is null. Might need to mock that as well.
Damien
You do it *exactly* as you do it for the `true` case, but change just this one line. Actually, just this one string. If the code you give works for `true`, as you claim, then there must be additional code you're not showing. Use that same code for this case.
Craig Stuntz
+2  A: 

The reason your are getting NullReferenceException is because you never stubbed the controller.Request object in your unit test and when you invoke the controller action which uses Request.IsAjaxRequest() it throws.

Here's how you could mock the context using Rhino.Mocks:

[TestMethod]
public void Test_Ajax()
{
    // arrange
    var sut = new HomeController();
    var context = MockRepository.GenerateStub<HttpContextBase>();
    var request = MockRepository.GenerateStub<HttpRequestBase>();
    context.Stub(x => x.Request).Return(request);
    // indicate AJAX request
    request.Stub(x => x["X-Requested-With"]).Return("XMLHttpRequest");
    sut.ControllerContext = new ControllerContext(context, new RouteData(), sut);

    // act
    var actual = sut.Index();

    // assert
    // TODO: ...
}

[TestMethod]
public void Test_Non_Ajax()
{
    // arrange
    var sut = new HomeController();
    var context = MockRepository.GenerateStub<HttpContextBase>();
    var request = MockRepository.GenerateStub<HttpRequestBase>();
    context.Stub(x => x.Request).Return(request);
    sut.ControllerContext = new ControllerContext(context, new RouteData(), sut);

    // act
    var actual = sut.Index();

    // assert
    // TODO: ...
}

And here's a better alternative (which I would personally recommend you) in order to avoid all the plumbing code. Using MVCContrib.TestHelper (which is based on Rhino.Mocks) your unit test might be simplified to this:

[TestClass]
public class HomeControllerTests : TestControllerBuilder
{
    private HomeController _sut;

    [TestInitialize()]
    public void MyTestInitialize() 
    {
        _sut = new HomeController();
        this.InitializeController(_sut);
    }

    [TestMethod]
    public void HomeController_Index_Ajax()
    {
        // arrange
        _sut.Request.Stub(x => x["X-Requested-With"]).Return("XMLHttpRequest");

        // act
        var actual = _sut.Index();

        // assert
        // TODO: ...
    }

    [TestMethod]
    public void HomeController_Index_Non_Ajax()
    {
        // act
        var actual = _sut.Index();

        // assert
        // TODO: ...
    }
}

Much prettier. It also allows you to write much more expressive asserts on the action results. Checkout the doc or ask if for more info is needed.

Darin Dimitrov
Cheers. Gonna try this (and that framework, seems like it will make my life easier. Will comment soon. Till then thanks again!
Damien