我一直在探讨Scott Guthrie在ASP.NET MVC Beta 1上的精彩帖子。在其中,他展示了对UpdateModel方法所做的改进以及它们如何改进单元测试。我已经重新创建了一个类似的项目,但是当我运行包含对UpdateModel的调用的UnitTest时,我会收到一个命名controllerContext参数的ArgumentNullException。
以下是相关位,从我的模型开始:
public class Country {
public Int32 ID { get; set; }
public String Name { get; set; }
public String Iso3166 { get; set; }
}
控制器操作:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Int32 id, FormCollection form)
{
using ( ModelBindingDataContext db = new ModelBindingDataContext() ) {
Country country = db.Countries.Where(c => c.CountryID == id).SingleOrDefault();
try {
UpdateModel(country, form);
db.SubmitChanges();
return RedirectToAction("Index");
}
catch {
return View(country);
}
}
}
最后我的单元测试失败了:
[TestMethod]
public void Edit()
{
CountryController controller = new CountryController();
FormCollection form = new FormCollection();
form.Add("Name", "Canada");
form.Add("Iso3166", "CA");
var result = controller.Edit(2 /*Canada*/, form) as RedirectToRouteResult;
Assert.IsNotNull(result, "Expected to be redirected on successful POST.");
Assert.AreEqual("Show", result.RouteName, "Expected to redirect to the View action.");
}
调用ArgumentNullException
时会抛出 UpdateModel
,消息“值不能为空。参数名称:controllerContext”。我假设UpdateModel
需要在执行测试期间不存在的System.Web.Mvc.ControllerContext
。
我也假设我在某处做错了,只需指向正确的方向。
请帮助!
答案 0 :(得分:5)
我不认为可以这样做,因为UpdateModel使用的TryUpdateModel引用了ControllerContext,当从单元测试调用时,它是null。我使用RhinoMocks来模拟或存根控制器所需的各种组件。
var routeData = new RouteData();
var httpContext = MockRepository.GenerateStub<HttpContextBase>();
FormCollection formParameters = new FormCollection();
EventController controller = new EventController();
ControllerContext controllerContext =
MockRepository.GenerateStub<ControllerContext>( httpContext,
routeData,
controller );
controller.ControllerContext = controllerContext;
ViewResult result = controller.Create( formParameters ) as ViewResult;
Assert.AreEqual( "Event", result.Values["controller"] );
Assert.AreEqual( "Show", result.Values["action"] );
Assert.AreEqual( 0, result.Values["id"] );
以下是来自www.codeplex.com/aspnet上的Controller.cs源的相关位:
protected internal bool TryUpdateModel<TModel>( ... ) where TModel : class
{
....
ModelBindingContext bindingContext =
new ModelBindingContext( ControllerContext,
valueProvider,
typeof(TModel),
prefix,
() => model,
ModelState,
propertyFilter );
...
}
答案 1 :(得分:2)
我遇到了同样的问题。在阅读了tvanfosson的解决方案之后,我尝试了一个不涉及模拟框架的简单解决方案。
将默认的ControllerContext添加到控制器,如下所示:
CountryController controller = new CountryController();
controller.ControllerContext = new ControllerContext();
这在单元测试时删除了错误。我希望这可以帮助其他人。
答案 2 :(得分:0)
或者您可以创建表单数据代理,例如
public class CountryEdit {
public String Name { get; set; }
public String Iso3166 { get; set; }
}
所以Controller.Action应该看起来像
public ActionResult Edit(Int32 id, CountryEdit input)
{
var Country = input.ToDb();
// Continue your code
}