2017-06-05 79 views
1

我在我的項目中使用Autofac IoC容器類的類,但我不能做一個單元測試在一個特定的類。我如何單元測試使用

考慮以下情形:

//Class to be tested 
public Class A 
{ 
    private SomeAutoFacClass B; 

    public void DoSomething() 
    { 
    B = scope.Resolve<ClassName>();// Resolve the object needed 
    // Do something with instance B 
    } 
} 

// Test class 
public Class ATest 
{ 
    private A a; 

    [test] 
    public void TestMethod() 
    { 
    a.DoSomething();//*This method causes a null reference exception as it tries to resolve the objects* 
    } 
} 

在上面的代碼,我不能夠到單元測試用例由於依賴注入其僅專用於該特定的類。 我該如何解決這個問題?我也嘗試使用Moq創建一個autofactainer。 但這也失敗了。

回答

4

你是不是能夠測試你的類的原因是因爲你的類發生在你的DI容器的依賴。這是Service Locator anti-pattern的實現。這是一個反模式,因爲:

與服務定位的問題是,它隱藏了一個類的依賴性,從而導致運行時錯誤而不是編譯時錯誤,以及使代碼更難以維持因爲你不清楚什麼時候會引入突破性的變化。

相反,設計圍繞你的類

  • 構造器注入的情況下,類是一個組件(包含應用程序行爲的一類),在那裏你注入一個類需要直接依賴通過構造函數
  • 方法注入當類是一個以數據爲中心的對象時就像一個實體一樣,這意味着依賴被提供給這個類的公共方法,其中的consumin g類只使用該依賴關係,但不存儲它。

組件都內置了您的DI容器和註冊在你的Composition Root,而以數據爲中心的對象是new代碼編了組成根目錄之外。在這種情況下,您需要將依賴關係傳遞給已經構建的對象。

如果您構建和測試組件,您的代碼通常如下所示:

public class ComponentA 
{ 
    private ClassName b; 

    public ComponentA(ClassName b) 
    { 
     this.b = b; 
    } 

    public void DoSomething() 
    { 
     // Do something with instance B 
    } 
} 

// Test class 
public Class ATest 
{ 
    [test] 
    public void TestMethod() 
    { 
     // Arrange 
     B b = new FakeB(); 

     var a = new ComponentA(b); 

     // Act 
     a.DoSomething(); 

     // Assert 
     // Check whether be was invoked correctly. 
    } 
} 

如果您構建和測試需要在其業務中的一個相關性的數據中心的目標,您的代碼通常如下所示:

public class EntityA 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 

    public void DoSomething(ClassName b) 
    { 
     // Do something with instance B 
    } 
} 

// Test class 
public Class ATest 
{ 
    [test] 
    public void TestMethod() 
    { 
     // Arrange 
     B b = new FakeB(); 

     var a = new EntityA { Name = "Bert", Age = 56 }; 

     // Act 
     a.DoSomething(b); 

     // Assert 
     // Check whether be was invoked correctly. 
    } 
} 

所以回答你最初的問題:

如何d o我單元測試使用IoC容器類的課程

你不知道。您的應用程序代碼不應該依賴於DI容器,因爲這會導致各種各樣的複雜問題,比如難以測試。

+0

這是非常好的解釋!更多這樣的SO。 – Seabizkit

-2

使用IoC容器,您應該着眼於使用IoC。通常這是建設者注入或屬性注入取決於你的容器可以支持自動注入。

我用從這種模式我稱之爲「懶人物業注入」在這裏我構造,注入我的容器作爲註冊表,然後用物業使用懶惰分辨率..

它看起來像什麼:

private readonly IoCContainer _container = null; 

private IMyService _myService = null; 
public IMyService MyService 
{ 
    get { return _myService ?? (_myService = _container.Resolve<IMyService>()); } 
    set { _myService = value; } 
} 

public MyClass(IoCContainer container) 
{ 
    if (container == null) 
     throw new ArgumentNullException("container"); 

    _container = container; 
} 

現在,當你去測試這個類的方法時,你的測試用Mock初始化你的MyService。在測試下運行時,我將IoCContainer初始化爲一個Mock(),如果發生任何.Resolve <>調用,則拋出它。這捕獲了您的代碼可能被修改爲使用尚未被嘲笑的新依賴關係的情況。

這種方法的好處是,往往一個班都會有幾個單一用途的方法,並通過擴展需要一些依賴。在Web請求等可能只調用一個方法的應用程序中,需要一個依賴項時,依賴性解析只會從容器中檢索所需的依賴項,而不是全部。 (即,如果使用具有8個依賴項的構造函數注入,則需要在運行時解析所有8個構造函數,即使只使用1個也是如此)。這還簡化了單元測試,以僅模擬出您知道需要的內容而不是所有內容。

+3

「我用這個模式稱爲」懶性屬性注入「,其中我的構造函數注入我的容器充當註冊表,然後使用屬性使用的懶惰解析」。該模式已有一個名稱,即:**服務定位器**和[它是反模式](http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/)。 – Steven

+0

某些服務定位器被認爲是反模式。我在使用容器時沒有任何負面的方式泄漏。如果在整個代碼中引用了IoC容器,那麼我會同意使用具有反模式的容器,但是使用它來通過封裝屬性來解析依賴關係不是。就我個人而言,我認爲使用IoC容器進行自動注入更像是一種反模式,因爲它充當了一個黑盒子,確切地說明了依賴關係如何被解析和注入。 –