I am working through Steve Sanderson’s book Pro ASP.NET MVC Framework and I having some issues with two unit tests which produce errors.
In the example below it tests the CheckOut ViewResult:
[AcceptVerbs(HttpVerbs.Post)]
public ViewResult CheckOut(Cart cart, FormCollection form)
{
// Empty carts can't be checked out
if (cart.Lines.Count == 0)
{
ModelState.AddModelError("Cart", "Sorry, your cart is empty!");
return View();
}
// Invoke model binding manually
if (TryUpdateModel(cart.ShippingDetails, form.ToValueProvider()))
{
orderSubmitter.SubmitOrder(cart);
cart.Clear();
return View("Completed");
}
else // Something was invalid
return View();
}
with the following unit test
[Test]
public void Submitting_Empty_Shipping_Details_Displays_Default_View_With_Error()
{
// Arrange
CartController controller = new CartController(null, null);
Cart cart = new Cart();
cart.AddItem(new Product(), 1);
// Act
var result = controller.CheckOut(cart, new FormCollection {
{ "Name", "" }
});
// Assert
Assert.IsEmpty(result.ViewName);
Assert.IsFalse(result.ViewData.ModelState.IsValid);
}
I have resolved any issues surrounding TryUpdateModel by upgrading to ASP.NET MVC 2 (Release Candidate 2) and the website runs as expected.
The associated error messages are:
Tests.CartControllerTests.Submitting_Empty_Shipping_Details_Displays_Default_View_With_Error:
System.ArgumentNullException : Value cannot be null.
Parameter name: controllerContext
and the more detailed
at System.Web.Mvc.ModelValidator..ctor(ModelMetadata metadata, ControllerContext controllerContext)
at System.Web.Mvc.DefaultModelBinder.OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
at System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
at System.Web.Mvc.Controller.TryUpdateModel[TModel](TModel model, String prefix, String[] includeProperties, String[] excludeProperties, IValueProvider valueProvider)
at System.Web.Mvc.Controller.TryUpdateModel[TModel](TModel model, IValueProvider valueProvider)
at WebUI.Controllers.CartController.CheckOut(Cart cart, FormCollection form)
Has anyone run into a similar issue or gotten the test to pass?
You have to mock the HttpContext of the Controller to write such tests. The MvcContrib library makes it quite easy.
Another option that I prefer is to extract the logic done by “TryUpdateModel” into a custom ModelBinder. You can then test the logic of your checkout action method separately from the logic that update your model.
No HttpContext needed.