2009-08-11 160 views
5

我只是想知道最好的做法是重新連接內核中的綁定。Ninject內核綁定覆蓋

我有一個內核類和一個私有類模塊與默認生產綁定類。

對於測試我想重寫這些綁定,所以我可以交換我的測試雙打/ Mocks對象。

確實

MyClass.Kernel.Load(new InlineModule(m=> m.Bind<IDepend>().To<TestDoubleDepend>())) 

覆蓋了IDepend任何現有的綁定?

回答

0

我會添加一個構造函數給接受模塊的MyClass。
這不會用於生產,但會用於測試。
在測試代碼中,我將傳遞一個定義所需測試雙精度的模塊。

1

我傾向於做的是有一個單獨的測試項目與它自己的綁定完成 - 我當然假設我們正在談論某種單元測試。測試項目使用自己的內核,並將測試項目中的模塊加載到該內核中。項目中的測試在CI構建過程中執行,並通過構建腳本執行完整構建來執行,儘管測試從未部署到生產環境中。

我意識到你的項目/解決方案設置可能不允許這種類型的組織,但它似乎是我見過的非常典型的。

5

我嘗試儘可能少地直接在我的代碼中使用DI內核,而不是依賴構造函數注入(或在特定情況下的屬性,例如Attribute類)。然而,在我必須使用抽象層的情況下,我可以設置DI內核對象,使其在單元測試中可以嘲弄。

例如:

public interface IDependencyResolver : IDisposable 
{ 
    T GetImplementationOf<T>(); 
} 

public static class DependencyResolver 
{ 
    private static IDependencyResolver s_resolver; 

    public static T GetImplementationOf<T>() 
    { 
     return s_resolver.GetImplementationOf<T>(); 
    } 

    public static void RegisterResolver(IDependencyResolver resolver) 
    { 
     s_resolver = resolver; 
    } 

    public static void DisposeResolver() 
    { 
     s_resolver.Dispose(); 
    } 
} 

使用這樣的模式,您可以通過調用RegisterResolver與模擬或假的實現,它返回任何你想要的對象,而不必線了全模塊設置爲從單元測試的IDependencyResolver 。它還具有從特定IoC容器中提取代碼的次要好處,如果您選擇在將來切換到另一個代碼。

當然,您還需要根據需要添加更多方法到IDependencyResolver,我只是將這裏的基礎知識作爲示例。是的,這會要求你在Ninject內核上編寫一個超級簡單的包裝器,它也實現了IDependencyResolver

你想這樣做的原因是,你的單元測試應該只是測試一件事情,並且通過使用你的實際IoC容器,你實際上比被測試的一個類運行得更多,這會導致錯誤的否定這會讓你的測試變得脆弱,並且(更重要的是)隨着時間的推移,讓開發人員相信他們的準確性。這可能會導致測試的冷漠和放棄,因爲測試失敗,但軟件仍然可以正常工作(「別擔心,總是失敗,這不是什麼大問題」)。

+0

對於解析器模式+1,但是,真的嘗試在使用IDepend的MyClass中使用構造器注入。這樣,你的單元測試甚至不需要你的IoC容器。 – 2010-09-23 17:16:43

+0

爲什麼不只是做一些更簡單的像重寫綁定一樣... var kernel = new StandardKernel(new ProductionModule(config)); ()。 kernel.Rebind ().To ().InSingletonScope(); – 2011-12-28 17:52:51

+0

您可以覆蓋綁定,但是您的測試也會測試您的DI容器以及待測試的單元。在某些情況下,這不是什麼大不了的事情,但正如我在答案中所概括的那樣,這可能會導致錯誤的否定並削弱測試套件的信任。 – krohrbaugh 2012-01-04 19:52:38

1

Peter Mayer的方法shuoul對於單元測試是有用的,但是恕我直言,使用構造函數/屬性注入手動注入Mock不是更容易嗎?

對我來說,使用特定綁定進行測試項目對其他類型的測試(集成,功能性)更有用,但即使在這種情況下,您仍然需要根據測試更改綁定。

我的方法是kronhrbaugh和Hamish Smith的混合,creatin是一種「依賴解析器」,您可以在其中註冊和取消註冊要使用的模塊。

+0

我其實同意你的意見。在大多數我自己的單元測試中,我正在做「手動」注入 - 這聽起來太簡單了,僅僅將模擬傳遞給構造函數!我在一些單獨的特定情況下使用了單元測試中的DI,但是肯定是少數情況。 – 2009-09-10 12:23:57

0

對於我正在開發的項目,我爲每個環境(測試,開發,舞臺,製作等)創建了單獨的模塊。這些模塊定義綁定。

因爲dev,stage和production都使用了很多相同的綁定,所以我創建了一個通用的模塊,它們都是從它們派生而來的。每個人然後添加它環境特定的綁定。

我也有一個KernelFactory,當交給一個環境令牌時,它會用適當的模塊來緩衝一個IKernel。

這使我可以切換我的環境令牌,它將自動更改我的所有綁定。

但是,如果這是單元測試,我同意上面的意見,一個簡單的構造函數允許手動綁定是一種方式,因爲它可以讓Ninject保持您的測試。

3

我只希望像這樣的作品

 var kernel = new StandardKernel(new ProductionModule(config)); 
     kernel.Rebind<ITimer>().To<TimerImpl>().InSingletonScope(); 

其中ProductionModule是我的生產綁定和我通過在特定的測試案例調用重新綁定覆蓋。我把重新綁定的幾件物品叫做rebind。

優點:如果有人向生產模塊添加新的綁定,我會繼承它們,這樣它就不會以這種方式破壞,這很好。這一切都在Java中的Guice中工作...希望它也能在這裏工作。