2011-05-09 63 views
0

我試圖按照typical pattern重寫ControllerContext以模擬HttpContext。在我的情況下,我特別想測試HTTP POSTS,所以我需要模擬Request.Form。MVC嘲笑HttpContext,模型綁定錯誤

我嘗試了所有在谷歌上找到的3種口味 - 與Moq,Rhino.Mocks和MVCContrib.TestHelpers。對於我的具體情況,我一直無法找到解決方案。

當我的控制器嘗試模型綁定,我得到以下錯誤:

Object reference not set to an instance of an object. 
System.NullReferenceException: Object reference not set to an instance of an object. 
at Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.CollectionReplacer.GetUnvalidatedCollections(HttpContext context) 
at System.Web.Helpers.Validation.Unvalidated(HttpRequest request) 
at System.Web.Mvc.FormValueProviderFactory.<.ctor>b__0(ControllerContext cc) 
at System.Web.Mvc.FormValueProviderFactory.GetValueProvider(ControllerContext controllerContext) 
at System.Web.Mvc.ValueProviderFactoryCollection.<>c__DisplayClassc.<GetValueProvider>b__7(ValueProviderFactory factory) 
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() 
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() 
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) 
at System.Linq.Enumerable.ToList(IEnumerable`1 source) 
at System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext) 
at System.Web.Mvc.Controller.TryUpdateModel(TModel model) 
at eServices.Admin.Web.Controllers.User.UserController.Search() in UserController.cs: line 56 
at eServices.Admin.Specs.Controllers.when_the_user_controller_is_posted_the_manage_users_find_form.<.ctor>b__1() in UserControllerSpecs.cs: line 96 

這似乎表明,它是沒有找到嘲笑的形式。下面是測試代碼片段:

MoqHttpContext MoqHttpContext = new MoqHttpContext(); 
var sut = new UserController(
      UserRepository, 
      EmailService, 
      SessionProvider); 

var controllerContext = new ControllerContext 
     (new RequestContext(MoqHttpContext.GetHttpContext(), new RouteData()), sut); 
sut.ControllerContext = controllerContext; 

MoqHttpContext.FormData.Add("FindCriteria.SearchText", "searchText"); 
MoqHttpContext.FormData.Add("FindCriteria.AccountIsPending", "true"); 

sut.Search(); 

...

控制器:

[AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult Search() 
    { 
     var manageUsersViewModel = new ManageUsersViewModel(); 
     TryUpdateModel(manageUsersViewModel); 

...

測試員額的任何意見或更好的解決方案?

回答

2

使用MvcContrib.TestHelper:是

// arrange 
var sut = new SomeController(); 
var tcb = new TestControllerBuilder(); 
tcb.InitializeController(sut); 
var formValues = new FormCollection() 
{ 
    { "FindCriteria.SearchText", "searchText" }, 
    { "FindCriteria.AccountIsPending", "true" }, 
}; 
sut.ValueProvider = formValues.ToValueProvider(); 

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

// assert 
... 

Any ideas or better solutions for testing POSTs?

:使用TryUpdateModel而不是有你的控制器動作直接將視圖模型參數:

[HttpPost] 
public ActionResult Search(ManageUsersViewModel model) 
{ 
    ... 
} 

然後在單元測試:

// arrange 
var sut = new SomeController(); 
var model = new ManageUsersViewModel 
{ 
    FindCriteria = new FindCriteria 
    { 
     SearchText = "searchText", 
     AccountIsPending = true 
    } 
}; 

// act 
var actual = sut.Search(model); 

// assert 
... 
+0

我在獲取操作的會話中存儲視圖模型(從服務調用填充),然後在調用TryUpdateModel之前檢索該視圖模型的後操作中。因爲我想在會話中保存從服務接收到的數據(或者將來可能會使用緩存),所以我依賴於TryUpdateModel。有沒有辦法通過動作參數的方式進行模型綁定,但是使用模型綁定可以工作的初始值,最初是從會話/緩存接收到的?希望這是有道理的 – jamiebarrow 2011-07-26 15:57:52