开发者

MVC mocked HttpContext, model binding error

开发者 https://www.devze.com 2023-03-04 03:54 出处:网络
I am trying to follow the typical pattern of overriding the ControllerContext in order to mock HttpContext. In my case I specifically want to test HTTP POSTS so i need to mock Request.Form.

I am trying to follow the typical pattern of overriding the ControllerContext in order to mock HttpContext. In my case I specifically want to test HTTP POSTS so i need to mock Request.Form.

I have tried all 3 flavours found on google - with Moq, with Rhino.Mocks and with the MVCContrib.TestHelpers. For my specifics I've not been able to find a solution.

When my controller tries to bind the model, i get the following error:

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 

Which appears to suggest it is not finding the mocked form. Here's the test code snippet:

MoqHttpContext MoqHttpCon开发者_高级运维text = 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();

...

in the controller:

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

...

Any ideas or better solutions for testing POSTs?


Using 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?

Yes: instead of using TryUpdateModel have your controller actions directly take the view model as argument:

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

then in your unit test:

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

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

// assert
...
0

精彩评论

暂无评论...
验证码 换一张
取 消