簡體   English   中英

NUnit Mocking不適用於Singleton方法

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM