在使用MVCContrib对unit testingMVC 3控制器和视图进行unit testing时,向RouteData添加键和值

好的,所以我使用MVCContrib TestHelper对我的控制器进行unit testing,效果很好。

和很多人一样,通过unit testing我真的是指这里的集成测试,我想至少确保我的视图在没有错误的情况下呈现给定模型提供…否则我会错过一大堆与模型基本相关的错误虽然我正在测试控制器(如果模型属性为null,则视图不呈现)。

无论如何,我开始试图弄清楚如何做到这一点(也就是谷歌搜索如何做到这一点)。 看起来最简单的方法是构造一个HTMLHelper并让它只渲染视图(在这种情况下是部分的)。

不幸的是,当我尝试使用我的模拟HTMLHelper时,它抱怨说路由数据中没有控制器名称。

果然,我看起来并没有填充控制器RouteData。 不幸的是,RouteData.Values RouteValueDictionary是只读的,所以我不能只提供必要的值。

我没有结合HTMLHelper的想法来解决实际渲染视图作为测试的一部分的问题,所以请随意提出替代方案,但请不要建议我使用Selenium,W​​atin或其他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); } 

顺便说一句,我得到的具体错误是: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的无参数构造函数,故意在那里允许模拟等。

您可以覆盖Controllers ControllerContext.RouteData – 它的虚拟和RouteData属性只是用它来读取。

从asp.net mvc RouteData属性的反映代码:

 public RouteData RouteData { get { return ControllerContext == null ? null : ControllerContext.RouteData; } }