【发布时间】:2012-05-23 15:49:15
【问题描述】:
我想编写一个单元测试来验证我的路由注册和 ControllerFactory,以便给定一个特定的 URL,一个特定的控制器将被创建。像这样的:
Assert.UrlMapsToController("~/Home/Index",typeof(HomeController));
我修改了“Pro ASP.NET MVC 3 Framework”一书中的代码,除了 ControllerFactory.CreateController() 调用抛出 InvalidOperationException 并显示 This method cannot be called during the application's pre-start initialization stage. 之外,这似乎是完美的。
于是我下载了MVC源码并调试进去,寻找问题的根源。它源自 ControllerFactory 寻找所有引用的程序集 - 以便它可以找到潜在的控制器。在 CreateController 调用堆栈的某处,具体的麻烦制造者调用是这样的:
internal sealed class BuildManagerWrapper : IBuildManager {
//...
ICollection IBuildManager.GetReferencedAssemblies() {
// This bails with InvalidOperationException with the message
// "This method cannot be called during the application's pre-start
// initialization stage."
return BuildManager.GetReferencedAssemblies();
}
//...
}
I found a SO commentary on this。我仍然想知道是否有可以手动初始化的东西来让上面的代码开心。任何人?
但是如果没有那个...我不禁注意到调用来自 IBuildManager 的实现。我探索了the possibility of injecting my own IBuildManager,但遇到了以下问题:
- IBuildManager 被标记为
internal,所以我需要一些其他的授权派生。原来程序集System.Web.Mvc.Test有一个类叫MockBuildManager,专为测试场景设计,完美!!!这就引出了第二个问题。 - 据我所知,MVC 可分发文件没有随 System.Web.Mvc.Test 程序集 (DOH!) 一起提供。
- 即使 MVC 可分发组件确实带有 System.Web.Mvc.Test 程序集,拥有
MockBuildManager的实例也只是解决方案的一半。还需要将该实例提供给DefaultControllerFactory。不幸的是,完成此操作的属性设置器也标记为internal(DOH!)。
简而言之,除非我找到另一种方法来“初始化”MVC 框架,否则我现在的选择是:
- 完全复制 DefaultControllerFactory 及其依赖项的源代码,这样我就可以绕过原来的
GetReferencedAssemblies()问题。 (啊!) - 完全用我自己构建的 MVC 替换 MVC 可分发,基于 MVC 源代码 - 只删除了几个
internal修饰符。 (双啊!)
顺便说一句,我知道 MvcContrib“TestHelper”看起来可以实现我的目标,但我认为它只是使用反射来查找控制器 - 而不是使用实际的 IControllerFactory 来检索控制器类型/实例。
我想要这个测试功能的一个重要原因是我已经创建了一个基于 DefaultControllerFactory 的自定义控制器工厂,我想验证它的行为。
【问题讨论】:
标签: asp.net asp.net-mvc asp.net-mvc-3 unit-testing