我想编写一个单元测试,验证我的路由注册和ControllerFactory,以便给定一个特定的URL,将创建一个特定的控制器。事情是这样的:测试ControllerFactory(预启动初始化阶段)
Assert.UrlMapsToController("~/Home/Index",typeof(HomeController));
我修改从书“临ASP.NET MVC 3框架”采取了代码,现在看来,这将是完美的除了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的自定义控制器工厂,该工厂的行为我想验证。
我遇到了同样的问题,试图测试从IOC容器中拉出控制器的自定义控制器工厂。所以我的用例是验证控制器是否从GetControllerInstance()方法中的IOC容器中提取了正确的控制器(由于它是受保护的,显然只能通过CreateController()访问,所以不能直接测试)。但是由于抛出的异常,代码并没有达到那么远。 – Thierry