我想編寫一個單元測試,驗證我的路由註冊和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