如何从Model对象为控制器分配valueprovider

时间:2015-01-03 22:25:35

标签: asp.net-mvc-4 unit-testing

我的MVC4应用程序中有一个Edit Post操作方法,我正在尝试对此操作进行单元测试。但是,单元测试失败了" NullReferenceException"。以下是单元测试FYR。

    [TestMethod]
    public void EditAction_Should_Redirect_When_Update_Successful()
    {
        // Arrange

        var mockHttpContext = new Mock<HttpContextBase>();            
        var mockRequest = new Mock<HttpRequestBase>();
        mockHttpContext.Setup(x => x.Request).Returns(mockRequest.Object);


        // tell the mock to return "POST" when HttpMethod is called      
        mockRequest.Setup(x => x.HttpMethod).Returns("POST");

        mockRequest.SetupGet(req => req.Form).Returns(new FormCollection());

        var controller = GetTheController();
        var id = 1;

        // assign the fake context
        var context = new ControllerContext(mockHttpContext.Object, 
              new RouteData(), 
              controller);
        controller.ControllerContext = context;


        var formValues = new MyModel() { 
             Id = 1,
             ActivityDescription = "This is another description",
             CreatedDate", Convert.ToDateTime("31-12-2014"),
             UserId = 1,
             IsCompleted = false
        };                                       

        // Act
        var result = controller.Edit(id, formValues) as RedirectToRouteResult;

        // Assert
        Assert.AreEqual("List", result.RouteValues["Action"]);
        Assert.AreEqual(id, result.RouteValues["id"]);
    }

编辑操作方法如下 -

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(MyModel item)
    {
        var viewResult = ValidateItem(item);
        if (viewResult != null)
            return viewResult;

        //Unit test is failing at this step.
        TryUpdateModel(item);
        if (ModelState.IsValid)
        {
            _itemsRepository.Edit(item);
            return RedirectToAction("Index");
        }
        else return View(item);
    }

以下是用于参考的堆栈跟踪 -

测试结果:失败 测试时间:0:00:00.3306816

结果讯息:

Test method MvcToDoListItemsDemo.Tests.TodoControllerTest.EditAction_Should_Redirect_When_Update_Successful threw exception: 
System.NullReferenceException: Object reference not set to an instance of an object.
Result StackTrace:  
at Microsoft.Web.Infrastructure.DynamicValidationHelper.DynamicValidationShim.IsValidationEnabled(HttpContext context)
   at Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.IsValidationEnabled(HttpContext context)
   at Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.GetUnvalidatedCollections(HttpContext context, Func`1& formGetter, Func`1& queryStringGetter)
   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[TSource](IEnumerable`1 source)
   at System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext)
   at System.Web.Mvc.ControllerBase.get_ValueProvider()
   at System.Web.Mvc.Controller.TryUpdateModel[TModel](TModel model)

有人可以告诉我这里是否做错了什么?

此致 拉姆

1 个答案:

答案 0 :(得分:1)

TryUpdateModel(item)从控制器的默认item获取ValueProvider的更新值,通常是System.Web.Mvc.FormValueProvider,后者从当前的POST请求正文中解析它们。在单元测试中,您可以将模型包装在DictionaryValueProvider<object>中并按原样返回,如下所示:

var controller = GetTheController();

var requestModel = new MyModel() 
{
  /* .. values .. */
};

controller.ValueProvider = new DictionaryValueProvider<object>(
    new Dictionary<string, object>() { { "MyModel", requestModel } }, null);

var result = controller.Edit(id) as RedirectToRouteResult;