我正在爲ASP.NET MVC 4編寫一個自定義的RazorViewEngine,並且我很難單元測試它,因爲基類正在調用那些上傳到BuildManager和VirtualPathProvider的東西拋出所有類型的異常,所以在我做的每一個新測試中,我都需要去除其他東西,因爲底層機制正在調用我沒有存根的對象,並拋出「對象引用未設置爲對象的實例。 「RazorViewEngine和單元測試
所以我所做的就是編寫一個類似於這個接口的接口,允許我將調用包裝到引擎的基類中。
internal interface IViewEngineDelegate
{
Func<ControllerContext, string, IView> CreatePartialView { get; set; }
Func<ControllerContext, string, string, IView> CreateView { get; set; }
Func<ControllerContext, string, bool> FileExists { get; set; }
Func<ControllerContext, string, bool, ViewEngineResult> FindPartialView { get; set; }
Func<ControllerContext, string, string, bool, ViewEngineResult> FindView { get; set; }
}
現在,我可以在我的生產代碼中執行以下操作。
public class CsEmbeddedRazorViewEngine : RazorViewEngine
{
private readonly IViewEngineDelegate _viewEngineDelegate;
public CsEmbeddedRazorViewEngine()
{
_viewEngineDelegate = new ViewEngineDelegate
{
CreatePartialView = base.CreatePartialView,
CreateView = base.CreateView,
FileExists = base.FileExists,
FindPartialView = base.FindPartialView,
FindView = base.FindView
};
}
internal CsEmbeddedRazorViewEngine(IViewEngineDelegate viewEngineDelegate)
{
_viewEngineDelegate = viewEngineDelegate;
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
// TODO: Do something.
return _viewEngineDelegate.CreatePartialView(controllerContext, partialPath)
}
}
最後,我可以測試它通過殘留電話,像這樣。
ViewEngineDelegate engineDelegate = new ViewEngineDelegate
{
CreatePartialView = (controllerContext, partialPath) => FakeViewFactory.Instance.Create(controllerContext, partialPath),
};
CsEmbeddedRazorViewEngine engine = new CsEmbeddedRazorViewEngine(engineDelegate);
經過一番思考我想到的只是這樣做,因爲我認爲我在工程設計,所以我決定去一個更簡單的方法。
public class CsEmbeddedRazorViewEngine : RazorViewEngine
{
protected sealed override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
// TODO: Do something.
return default(IView);
}
protected virtual IView CreatePartialViewCore(ControllerContext controllerContext, string partialPath)
{
return base.CreatePartialView(controllerContext, partialPath);
}
}
我不是很滿意,這兩種方法中的一種,這就是我張貼關於它的原因,我不知道是否有這樣做,或者還有更好的辦法,也許這只是我,這些都是可接受/合理的方法。