2009-06-09 90 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 
} 
相關問題