我想编写一个单元测试来验证我的路由注册和 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();
}
//...
}
我发现了一个关于这个的评论。我仍然想知道是否有可以手动初始化的东西来让上面的代码快乐。任何人?
但是在没有那个的情况下......我不禁注意到调用来自 IBuildManager 的实现。我探索了注入自己的 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 的自定义控制器工厂,我想验证它的行为。