好的,所以我正在使用MVCContrib TestHelper来对我的控制器进行单元测试,这很有用.
像这么多人一样,通过单元测试我真的意味着这里的集成测试,我想至少确保我的视图在给出模型提供的情况下无错误地呈现…否则我可以错过一个基本上与模型相关的一类bug,甚至虽然我正在测试控制器(如果模型属性为null,则视图不呈现).
无论如何,我开始试图找出如何做到这一点(又名谷歌如何做到这一点).看起来最简单的方法是构造一个HTMLHelper,并且只是渲染视图(在这种情况下是局部的).
不幸的是,当我尝试使用我嘲笑的HTMLHelper时,它抱怨说没有路由数据中的控制器名称可用.
果然,我看到控制器RouteData没有填充.不幸的是RouteData.Values RouteValueDictionary是只读的,所以我不能提供必要的值.
我没有结婚HTMLHelper的想法来解决实际渲染视图作为测试的一部分的问题,所以随时建议替代品,但请不要打扰建议我使用Selenium,Watin或其他UI测试我的意见测试工具…我希望控件能够做一些操作和恢复状态和数据信息的一些测试,我不能用基于UI的测试.
这是我目前正在尝试渲染部分的代码:
public class FakeView : IView { #region IView Members public void Render(ViewContext viewContext,System.IO.TextWriter writer) { throw new NotImplementedException(); } #endregion } public class WebTestUtilities { public static void prepareCache() { SeedDataManager seed = new SeedDataManager(); seed.CheckSeedDataStatus(); } public static string RenderRazorViewToString(string viewName,object model,Controller controller) { var sb = new StringBuilder(); var memWriter = new StringWriter(sb); var html = new HtmlHelper(new ViewContext(controller.ControllerContext,new FakeView(),new ViewDataDictionary(),new TempDataDictionary(),memWriter),new ViewPage()); //This fails because it can't extract route information like the controller name) html.RenderPartial(viewName,model); return sb.ToString(); } public void setupTestEnvironment(Controller controller) { RouteTable.Routes.Clear(); RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); RouteTable.Routes.MapRoute( "Default","{controller}/{action}/{id}",new { controller = "Main",action = "DefaultView",id = UrlParameter.Optional } ); ModelBinders.Binders[typeof(DateTime)] = new DateTimeModelBinder(); ModelBinders.Binders[typeof(DateTime?)] = new DateTimeModelBinder(); ModelMetadataProviders.Current = new DateTimeMetadataProvider(); } }
这里是我的测试方法:
[TestMethod] public void GetUserTableView() { ViewResult result = controller.UserTable() as ViewResult; //I can populate the route and handler on the controller... RouteData routes = RouteTable.Routes.GetRouteData(controller.HttpContext); controller.RouteData.Route = routes.Route; controller.RouteData.RouteHandler = routes.RouteHandler; RouteValueDictionary routeKeys = new RouteValueDictionary(); routeKeys.Add("controller","UserManagement"); routeKeys.Add("action","UserTable"); //But the RouteData.Values collection is read only :( controller.RouteData = new RouteData(){Values = routeKeys}; string renderedView = WebTestUtilities.RenderRazorViewToString(result.ViewName,result.Model,controller); }
BTW,我得到的具体错误是:
RouteData必须包含一个名为“controller”的项,其值为非空字符串值.
解决方法
你可能已经完成了这个工作,但是我也遇到了类似的问题,并通过在控制器上重新设置ControllerContext来解决设置RouteData的情况,如下所示:
RouteData routeData = new RouteData(); routeData.Values.Add("someRouteDataProperty","someValue"); ControllerContext controllerContext = new ControllerContext { RouteData = routeData }; controller.ControllerContext = controllerContext;
然后在控制器RouteData.Values.ContainsKey(“someRouteDataProperty”)中工作,就像您在测试中设置的那样.
这是因为有一个无参数的ControllerContext的构造函数,故意在那里允许嘲笑等