[英]NUnit Mocking not working for Singleton Method
忍受我,我是NUnit的新手。 我來自Rails之地,所以其中一些對我來說是新的。
我有一行代碼如下:
var code = WebSiteConfiguration.Instance.getCodeByCodeNameAndType("CATALOG_Brands_MinQty", item.Catalog);
我試圖模仿它,就像這樣(假設code
已經初始化):
var _websiteConfigurationMock = new DynamicMock(typeof(WebSiteConfiguration));
_websiteConfigurationMock.ExpectAndReturn("getCodeByCodeNameAndType", code);
當我調試測試時, getCodeByCodeNameAndType
返回null
,而不是預期的code
。 我究竟做錯了什么?
NUnit版本:2.2.8
對不起,我從未使用過NUnit.Mocks - 但我確實對NMock和Moq有一些經驗[順便說一句,我強烈推薦]。 通常,您使用模擬庫來生成接口定義的代理,並且我假設NUnit.Mocks以相同的方式操作。
因此,如果你想嘲笑你的單身人士,你可能需要做以下事情,
一種。 比如創建一個界面
// All methods you would like to mock from this class, should
// be members of this interface
public interface IWebSiteConfiguration
{
// Should match signature of method you are mocking
CodeType getCodeByCodeNameAndType (
string codeString,
CatalogType catalogType);
}
灣 “實施”界面
// You've already written the method, interface matches signature,
// should be as easy as slapping interface on class declaration
public class WebSiteConfiguration : IWebSiteConfiguration { }
C。 消費界面
好吧,所以步驟c。 是你大部分工作的地方。 從邏輯上講,如果你在嘲笑你的單身人士,你實際上是對消費者進行單元測試[你已經從你的樣本中留下了]。 對於c。 只需將一個參數添加到使用者的ctor中,或添加Type'IWebSiteConfiguration'的可公開訪問的屬性,然后在內部引用實例成員並針對此新接口調用您的方法。 想想這個,
是
public class MyClass
{
public MyClass () { }
public void DoSomething ()
{
// bad singleton! bad boy! static references are bad! you
// can't change them! convenient but bad!
code = WebSiteConfiguration.Instance.getCodeByCodeNameAndType (
"some.string",
someCatalog)
}
}
變
public class MyClass
{
private readonly IWebSiteConfiguration _config = null;
// just so you don't break any other code, you can default
// to your static singleton on a default ctor
public MyClass () : this (WebSiteConfiguration.Instance) { }
// new constructor permits you to swap in any implementation
// including your mock!
public MyClass (IWebSiteConfiguration config)
{
_config = config;
}
public void DoSomething ()
{
// huzzah!
code = _config.getCodeByCodeNameAndType ("some.string", someCatalog)
}
}
在單元測試中,創建模擬,將模擬的引用傳遞給使用者,並測試使用者。
[Test]
public void Test ()
{
IWebSiteConfiguration mockConfig = null;
// setup mock instance and expectation via
// NUnit.Mocks, NMock, or Moq
MyClass myClass = new MyClass (mockConfig);
myClass.DoSomething ();
// verify results
}
這也是依賴注入[DI]的實用介紹。 它只是向服務提供者傳遞或“注入”服務引用(例如您的網站配置類)的做法,而不是讓消費者直接調用服務[例如通過靜態單例類]。
希望這可以幫助 :)
DynamicMock在內存中創建一個新對象,表示要模擬的接口或marshallable(繼承自MarshalByRef)類。
嘗試這個:
var _websiteConfigurationMock = new DynamicMock(typeof(WebSiteConfiguration));
_websiteConfigurationMock.ExpectAndReturn("getCodeByCodeNameAndType", code);
WebSiteConfiguration conf = (WebSiteConfiguration)_websiteConfigurationMock.MockInstance;
var x = conf.getCodeByCodeNameAndType("CATALOG_Brands_MinQty", item.Catalog);
請注意,除非WebSiteConfiguration繼承MarshalByRef,否則第三行將無效。
你通常做的是模擬一個接口並獲得一個實現這個接口的新對象,但是按照你配置它的方式行事,而不必為它做一個具體的類型,所以我不完全確定是什么除非你使用更好的隔離框架,比如可以攔截對現有對象中的靜態方法/屬性的調用的TypeMock,你所做的就是工作。
似乎有一種使用反射的解決方案,或者我可能完全誤解了這一點。
這里討論: http : //www.geekbeing.com/2010/05/23/how-to-unit-test-singleton-hack-in-c
真的有效嗎?
public class TestableSingleton : SingletonClass
{
public TestableSingleton ()
{
FieldInfo fieldInfo = typeof(SingletonClass)
.GetField("_instance",
BindingFlags.Static | BindingFlags.NonPublic);
fieldInfo.SetValue(Instance, this);
}
}
項目可在https://github.com/rbabreu/TestableSingleton上獲得
實際上我無法在Visual Studio上編譯它,因為SingletonClass會有一個私有構造函數。 如果有人讓它工作將是很好的,以避免適配器模式的開銷。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.