特定の URL を指定すると、特定のコントローラーが作成されるように、ルート登録と ControllerFactory を検証する単体テストを作成したいと考えています。このようなもの:
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();
}
//...
}
これに関するSOの解説を見つけました。上記のコードを満足させるために手動で初期化できるものがあるかどうかはまだ疑問です。誰?
しかし、それがなければ...呼び出しが IBuildManager の実装から来ていることに気付かずにはいられません。独自の IBuildManager を注入する可能性を探りましたが、次の問題に遭遇しました。
- IBuildManager は とマークされ
internal
ているので、そこから他の承認された派生物が必要です。アセンブリSystem.Web.Mvc.Test
には、テスト シナリオ用に設計された というクラスがありMockBuildManager
、これは完璧です!!! これは 2 番目の問題につながります。 - 私が知る限り、配布可能な 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 に基づいてカスタム コントローラー ファクトリを作成したからです。