正如您發現的那樣,您不能使用大多數模擬庫來模擬密封類型。其中一個原因是,許多模擬庫通過創建派生類型來運行,但是如果該類是密封的,那麼它們不能從中派生出來。
我們在微軟內部完成的工作是我們使用手寫的IClientScriptManager
接口,然後使用ClientScriptManagerWrapper
實現該接口並將所有調用委託給實際的ClientScriptManager
。
然後無論什麼類型需要使用ClientScriptManager
它將代替IClientScriptManager
。在運行時,我們創建一個ClientScriptManagerWrapper
(並傳入實際的ClientScriptManager
)。在測試時間,我們使用一個模擬對象庫來創建一個模擬IClientScriptManager
並使用它。
下面是一個代碼示例:
public class SomeClassThatNeedsClientScriptManager {
private IClientScriptManager _iClientScriptManager;
public IClientScriptManager IClientScriptManager {
get {
if (_iClientScriptManager == null) {
_iClientScriptManager = new ClientScriptManagerWrapper(Page.ClientScriptManager);
}
return _iClientScriptManager;
}
set {
_iClientScriptManager = value;
}
}
public void SomeMethodThatUsesClientScriptManager() {
IClientScriptManager.RegisterClientScriptBlock(typeof(Whatever), "key", "alert('hello')");
}
}
public interface IClientScriptManager {
void RegisterClientScriptBlock(Type type, string key, string script);
}
public class ClientScriptManagerWrapper : IClientScriptManager {
private readonly ClientScriptManager _clientScriptManager;
public ClientScriptManagerWrapper(ClientScriptManager clientScriptManager) {
if (clientScriptManager == null) {
throw new ArgumentNullException("clientScriptManager");
}
_clientScriptManager = clientScriptManager;
}
public void RegisterClientScriptBlock(Type type, string key, string script) {
_clientScriptManager.RegisterClientScriptBlock(type, key, script);
}
}
然後,您可以修改IClientScriptManager
接口和ClientScriptManagerWrapper
有你需要的任何方法。
這太糟糕了,這是內部的。我希望看到更多的Framework類型實現公共接口和包裝,以便可測試的代碼可以與更少的層進行互操作。但這就是爲什麼我們傾向於包裝包裝。 :) – maxwellb 2014-01-17 23:01:02
@maxwellb的確,如果你看看大多數較新的框架(當然在ASP.NET空間中),你會看到更多的接口和抽象基類。例如,MVC,Web API和SignalR都大量使用接口,這使得這種場景更容易實現。 – Eilon 2014-01-20 17:06:16