2009-06-09 114 views
146

我使用ASP.Net MVC框架在C#中的控制器如何在ASP.Net MVC中模拟控制器上的请求?

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

我得到了嘲笑,并希望能与以下和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); 

但是我一直对代码进行测试的一些技巧收到此错误:

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

由于控制器上的Request对象没有制定者。我试图通过使用下面答案中的推荐代码来正确地工作。

过去,这起订量,而不是RhinoMocks,并且在使用起订量我使用了相同的测试如下:

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); 

但出现以下错误:

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)

再次,好像我无法设置请求标题。 如何在RhinoMocks或Moq中设置此值?

+0

用Request.IsAjaxRequest()替换Request.IsAjaxRequest() – 2009-06-09 14:22:22

+0

模拟Request.Headers [“X-Requested-With”]或Request [“X-Requested-With”]而不是Request.IsAjaxRequest()。我已经更新了我的问题 – 2009-06-09 16:16:01

+0

[试试这个(http://stackoverflow.com/questions/1228179/mocking-httpcontextbase-with-moq) – danfromisrael 2010-06-20 07:34:33

回答

190

使用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); 

更新:

模拟Request.Headers["X-Requested-With"]Request["X-Requested-With"]而不是Request.IsAjaxRequest()

+1

我收到消息“方法的类型参数'ISetupGetter Moq.Mock .SetupGet ....不能从uage传入,请尝试明确指定类型参数 ? 我设置什么类型的“变种请求=”来,虽然得到这个工作 – Nissan 2009-06-09 14:14:47

+0

刚刚更新我的答案 - 不是Request.IsAjaxRequest但Request.IsAjaxRequest()更新你的问题太 – 2009-06-09 14:21:42

+0

仍然会产生: 异常 \t系统。 .ArgumentException信息:System.ArgumentException: \t X => x.IsAjaxRequest() :非覆盖的构件上设置无效在Moq.Mock.ThrowIfCantOverride(表达式设置,MethodInfo methodInfo) – Nissan 2009-06-09 14:51:38

3

您需要模拟HttpContextBase,并把它变成你的ControllerContext属性,像:

controller.ControllerContext = 
new ControllerContext(mockedHttpContext, new RouteData(), controller); 

在这里,您可以看到如何嘲笑Form集合,您的方案将类似于:Mocking the HttpRequest in ASP.NET MVC

+0

和什么会mockedHttpContext需要被嘲笑?它需要的RequestContext对象需要构造函数中的HttpContextBase()对象,并且HttpContextBase()没有接受零参数的构造函数。 – Nissan 2009-06-09 14:00:59

+0

只是使用一个模拟框架,不要尝试直接构建这些对象... – 2009-06-09 14:35:16

+0

我试过了: var mocks = new MockRepository(); var mockedhttpContext = mocks.DynamicMock (); var mockedHttpRequest = mocks.DynamicMock (); SetupResult.For(mockedhttpContext.Request).Return(mockedHttpRequest); var controller = new HomeController(Repository,LoginInfoProvider); controller.ControllerContext = new mockedhttpContext,new RouteData(),controller); var result = controller.Index()as ViewResult; 但仍然得到相同的异常抛出。 – Nissan 2009-06-09 14:45:03

5

AjaxRequest是一种扩展方法。所以你可以用下面的方法使用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); 
12

这是一个使用RhinoMocks的工作解决方案。我系统是基于一个起订量的解决方案,我发现在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); 
} 
1

为了IsAjaxRequest()你需要设置请求头单元测试,以及请求的收藏价值都在您的测试方法,下面给出期间返回false:

_request.SetupGet(x => x.Headers).Returns(new System.Net.WebHeaderCollection { { "X-Requested-With", "NotAjaxRequest" } }); 
_request.SetupGet(x=>x["X-Requested-With"]).Returns("NotAjaxRequest"); 

这将在下面给出的原因用于建立都被隐藏在实施IsAjaxRequest()的:

public static bool IsAjaxRequest(this HttpRequestBase request)<br/> 
{ 
    if (request == null) 
    { 
     throw new ArgumentNullException("request"); 
    } 
    return ((request["X-Requested-With"] == "XMLHttpRequest") || ((request.Headers != null) && (request.Headers["X-Requested-With"] == "XMLHttpRequest"))); 
} 

它采用b另外请求集合和标题,这就是为什么我们需要为标题和请求集合创建设置。

这会使请求在不是ajax请求时返回false。使其返回true,你可以做到以下几点:

_httpContext.SetupGet(x => x.Request["X-Requested-With"]).Returns("XMLHttpRequest"); 
11

对于使用NSubstitute我能修改上面的答案,做这样的事情的人...(其中细节操作方法的名称在控制器上)

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); 
2

看起来你正在寻找这一点,在控制器

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

用法:

public ActionResult Index() 
{ 
     var age = Request["Age"]; //This will return 2001 
} 
相关问题