2011-02-16 58 views
2

我用這個Service Locator模式在我的應用程序,並實現爲單例:相關測試

Service Locator Pattern

,現在我想測試它。所以到目前爲止,我已經寫了一個測試,驗證我的課是單身人士。我也寫一下測試:

[Test] 
[ExpectedException(typeof(ApplicationException))] 
public void GetService_Throws_Exception_When_Invalid_Key_Is_Provided() 
{ 
    locator.GetService<IRandomService>(); 
} 

但我真的不喜歡最後的測試,因爲我永遠不會使用IRandomService。所以我正在尋找更好的方法來測試GetService<T>引發異常。另外我想知道是否還有其他相關測試可以爲這堂課寫作。

我使用的是最新版本的NUnit。

乾杯

回答

2

但我真的不喜歡最後的測試,因爲我永遠不會使用IRandomService

但這就是關鍵所在。你在測試設置方法(排列)中連接你的定位器,然後你查找一個沒有連線的鍵(act),然後檢查是否引發了一個異常(斷言)。你不需要使用你實際使用的類型,你只是想確信你的方法正在工作。

另外我想知道是否有任何其他的相關測試,我可以寫這個類。

嗯,我要在這裏回答一個不同的問題。

服務定位器模式是否邪惡?

是的,這是純粹的邪惡。

它破壞了依賴注入的目的,因爲它不會使依賴顯式化(任何類都可以將任何東西拉出服務定位器)。而且,它使你的所有組件都依賴於這一個類。

它使維護成爲一個令人難以置信的噩夢,因爲現在你有這個組件只是遍佈在你的代碼庫。你已經與這個課程緊密結合了。

此外,測試是一場噩夢。假設您有

public class Foo { 
    public Foo() { // } 
    public string Bar() { // } 
} 

並且您要測試Foo.Bar

public void BarDoesSomething() { 
    var foo = new Foo(); 
    Assert.Equal("Something", foo.Bar()); 
} 

和運行測試,你會得到一個異常

ServiceLocator could not resolve component Frob. 

什麼?哦,那是因爲你的構造函數看起來像這樣:

public Foo() { 
    this.frob = ServiceLocator.GetService<Frob>(); 
} 

而且。

迴避,躲避,迴避。

4

有些事情:

  • 一個試驗來驗證類是單?單例模式將確保嘗試將單例作爲實例類來處理,甚至不會編譯。如果你還沒有寫你的服務定位類似下面的,這是錯誤的:

Singleton模式在C#:

public class MySingleton() 
{ 
    //Could also be a readonly field, or private with a GetInstance method 
    public static MySingleton Instance {get; private set;} 
    static MySingleton() 
    { 
     Instance = new MySingleton(); 
    } 
    private MySingleton() { ... } 
} 

... 

//in external code 
var mySingletonInstanceRef = MySingleTon.Instance; //right 
var mySingletonInstanceRef = new MySingleton(); //does not compile 

//EDIT: The thread-safe lazy-loaded singleton 
public class MySingleton() 
{ 
    //static fields with initializers are initialized on first reference, so this behaves lazily 
    public static readonly MySingleton instance = new MySingleton(); 
    //instead of the below you could make the field public, or have a GetInstance() method 
    public static MySingleton Instance {get{return instance;} 

    private MySingleton() { ... } 
} 
  • 服務定位器是一個反模式。這聽起來不錯,但它並不能真正解決它所創造的問題。主要的問題是它將你緊緊地與服務定位器相連接;如果定位符更改,則每個使用它的類都會更改。相比之下,依賴注入可以在沒有花哨框架的情況下完成;你只需確保任何複雜的,昂貴的,可重用的對象通過其構造函數傳遞給需要它的對象。 DI/IoC框架只是通過確保提供所需對象的所有已知依賴關係來簡化此過程,即使圖中的某個對象無法瞭解其子項的依賴關係。

  • 您已經開發的類。 TDD/BDD的精神在於您編寫的測試能夠證明您尚未編寫的代碼是正確的。我不是說現在編寫測試不會達到目的,但是一個失敗的測試需要打開並修復該對象,並且如果代碼已經集成,則可能會破壞其他內容。

  • 單元測試大量使用結構,將永遠不會看到生產。存在Mock,存根,代理和其他「測試助手」以將被測對象與其通常集成的環境隔離開,保證如果輸入是A,B和C,則被測對象將執行X,無論是否它通常會將它賦予A,B和C.因此,不要擔心創建簡單的構造,例如您不會在生產中使用的骨架接口;只要它能很好地表示你在測試用例中所期望的輸入,那就沒有問題。

1

我不太明白你的問題。你是否不滿意要求一種你永遠不會在生產中使用的類型?您是否對服務定位器使用不符合生產代碼的方式感到不滿?測試本身對我來說看起來很好 - 你正在請求一些不存在的東西,並證明發生了預期的行爲。對於單元測試來說,這樣做是完全合理的。當我們使用依賴注入容器是我們的佈線應用相分離成模塊,然後我們會嘗試在集成測試解決根本類型,以確保應用程序能夠進行佈線做

一兩件事。如果佈線測試失敗,這是一個很好的跡象表明該應用程序無法正常工作(儘管它沒有證明應用程序工作)。在使用服務定位器時做這種事情會更有效率。

我百分之百同意與Jason,太 - 服務定位器似乎是一個好主意,但很快變得不可收拾。他們'拉'(使用服務定位器實例的類型必須與其耦合),而依賴注入容器的'推'(絕大多數應用程序是DI不可知的,因此代碼更脆弱,更可重用)。

一對夫婦的其他東西:

  1. [ExpectedException]已被棄用。 使用Assert.Throws 而不是
  2. ApplicationException是 也被棄用。
+0

我是一個新手,以測試和所有theese模式。所以基本上我只是在練習。我應該使用什麼樣的異常而不是applicationException? – Ols1 2011-02-16 19:08:41

相關問題