问题
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
回答1:
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.
回答2:
Expect.Call(_myController.Request.Headers["X-Requested-With"]).Return("SpitAndDuctTape").Repeat.Any();
...should do the job.
来源:https://stackoverflow.com/questions/3068589/mocking-ajax-isrequest-to-return-false