2015-04-02 81 views
1

我希望測試的C#類接受同一接口的IEnumerable實例。我使用Ninject進行依賴注入。我怎麼會注入使用Ninject MockingKernel起訂量使用Ninject MockingKernel Moq如何爲同一接口注入多個模擬

public class Foo: IFoo 
{ 
    private readonly Dictionary<ContextType, IBar> _bars; 
    public Foo(IEnumerable<IBar> bars) 
    { 
     _bars= bars.ToDictionary(x => x.ContextType); 
    } 
} 
public interface IBar 
{ 
    ContextType ContextType { get; } 
    void DoStuff(); 
} 
public enum ContextType 
{ 
    Local, 
    Site, 
    Test 
} 

嘲笑到了IEnumerable這是我的正常結合的模樣

//assume _kernel is StandardKernel 
_kernel.Bind<IFoo>().To<MyFoo>(); 
_kernel.Bind<IBar>().To<Bar1>(); //ContextType.Site 
_kernel.Bind<IBar>().To<Bar2>(); //ContextType.Local 
_kernel.Bind<IBar>().To<Bar3>(); //ContextType.Test 

設置如下圖所示嘲笑如何注入只剩下最後模擬成富(如應該注射3次)

//using _kernel = new MoqMockingKernel() 
_kernel.Bind<IFoo>().To<MyFoo>(); 
var bar1Mock = _kernel.GetMock<IBar>();barMock1.Setup(m=>m.ContextType).Returns(ContextType.Site); 
var bar2Mock = _kernel.GetMock<IBar>();barMock2.Setup(m=>m.ContextType).Returns(ContextType.Local); 
var bar3Mock = _kernel.GetMock<IBar>();barMock3.Setup(m=>m.ContextType).Returns(ContextType.Test); 

_foo = _kernel.Get<IFoo>(); 

任何幫助表示讚賞。謝謝

+0

當兩次綁定到同一個接口時,實際上是_overriding_上一個綁定,而不是添加一個新綁定。所以實際上,當在代碼中的任何地方解析「IBar」時,「Bar3」類型將被實例化。你能更清楚地解釋,你想達到什麼目的? – Yura 2015-04-02 18:54:08

+0

我有一個策略模式與IBar的ContextType屬性作爲關鍵。所以,我將多個策略(酒吧)注入Foo,並且希望在測試期間爲每個策略注入模擬。 – JRT 2015-04-02 19:18:18

回答

0

爲什麼不只是手動實例化Foo,如果你是單元測試它?

var bar1Mock = _kernel.GetMock<IBar(); 
barMock1.Setup(m=>m.ContextType).Returns(ContextType.Site); 
var bar2Mock = _kernel.GetMock<IBar>(); 
barMock2.Setup(m=>m.ContextType).Returns(ContextType.Local); 
var bar3Mock = _kernel.GetMock<IBar>(); 
barMock3.Setup(m=>m.ContextType).Returns(ContextType.Test); 

// simply create new instance, what is a point o 
var target = new Foo(new[]{barMock1.Object, bar2Mock.Object, bar3Mock.Object }); 

但是,如果你理解你的權利,你想要IEnumerable<IBar> bars由Ninject? 然後,你需要使用Ninject綁定實際徵收:

var allBars = new []{new Bar1(), new Bar2(), new Bar3()}; 
kernel.Bind<IEnumerable<IBar>>().ToConstant(allBars); 

或者,嘗試實際上陣列的IBar代替IEnumerable<IBar>,並留下您的綁定,就是:

_kernel.Bind<IFoo>().To<MyFoo>(); 
_kernel.Bind<IBar>().To<Bar1>(); //ContextType.Site 
_kernel.Bind<IBar>().To<Bar2>(); //ContextType.Local 
_kernel.Bind<IBar>().To<Bar3>(); 

public class Foo: IFoo 
{ 
    private readonly Dictionary<ContextType, IBar> _bars; 
    public Foo(IBar[] bars) 
    { 
     _bars= bars.ToDictionary(x => x.ContextType); 
    } 
} 

根據manual,這應該工作。

更新:綁定到實際模擬的情況下,後決心的IFoo像往常一樣:

var bar1Mock = _kernel.GetMock<IBar(); 
barMock1.Setup(m=>m.ContextType).Returns(ContextType.Site); 
var bar2Mock = _kernel.GetMock<IBar>(); 
barMock2.Setup(m=>m.ContextType).Returns(ContextType.Local); 
var bar3Mock = _kernel.GetMock<IBar>(); 
barMock3.Setup(m=>m.ContextType).Returns(ContextType.Test); 

_kernel.Bind<IBar>().ToConstant(bar1Mock.Object); 
_kernel.Bind<IBar>().ToConstant(bar2Mock.Object); 
_kernel.Bind<IBar>().ToConstant(bar3Mock.Object); 

foo = _kernel.Get<IFoo>(); 

UPDATE2:嘗試這種方式

_kernel.Bind<IBar>().ToMethod(x => bar1Mock.Object); 
_kernel.Bind<IBar>().ToMethod(x => bar2Mock.Object); 
_kernel.Bind<IBar>().ToMethod(x => bar3Mock.Object); 
+0

我可以手動實例化一個新的Foo實例,但我希望Ninject來處理它。另外通過傳遞barMock.Objects 1,2和3的數組來手動實例化一個新的Foo - 不起作用。所有三個都是最後一個測試類型 – JRT 2015-04-02 19:58:23

+0

IBar [] bars'構造函數是否成功? – Yura 2015-04-02 19:59:08

+0

我可以使用ninject注入非模擬Bar1,Bar2和Bar3。沒問題,但我需要注入3 mockBars – JRT 2015-04-02 20:03:52

0

我有這個工作了。 _kernel需要在請求另一個獨特的同一接口模擬之前被重置。下面這段代碼工作

var bar1Mock = _kernel.GetMock<IBar();barMock1.Setup(m=>m.ContextType).Returns(ContextType.Site); 
_kernel.Reset(); 

var bar2Mock = _kernel.GetMock<IBar>();barMock2.Setup(m=>m.ContextType).Returns(ContextType.Local); 
_kernel.Reset(); 

var bar3Mock = _kernel.GetMock<IBar>(); barMock3.Setup(m=>m.ContextType).Returns(ContextType.Test); 
_kernel.Reset(); 

_kernel.Bind<IBar>().ToConstant(bar1Mock.Object); 
_kernel.Bind<IBar>().ToConstant(bar2Mock.Object); 
_kernel.Bind<IBar>().ToConstant(bar3Mock.Object); 

感謝

0

運行到同樣的問題。上面的答案沒有幫助。 下面是一個解決方案,但它不是理想的。

使用kernel.Reset();似乎不正確。

類似的代碼

var bar1Mock = _kernel.GetMock<IBar() 
barMock1.Setup(m=>m.ContextType).Returns(ContextType.Site); 
var bar2Mock = _kernel.GetMock<IBar>(); 
barMock2.Setup(m=>m.ContextType).Returns(ContextType.Local); 
var bar3Mock = _kernel.GetMock<IBar>(); 
barMock3.Setup(m=>m.ContextType).Returns(ContextType.Test); 

_kernel.Bind<IBar>().ToMethod(x => bar1Mock.Object); 
_kernel.Bind<IBar>().ToMethod(x => bar2Mock.Object); 
_kernel.Bind<IBar>().ToMethod(x => bar3Mock.Object); 

foo = _kernel.Get<IFoo>(); 

仍然返回鏈接到同一個(最後一個)模擬。也許我錯過了什麼?

我想用嘲諷的內核,但到目前爲止,我得到了最好的是:

var barMock1 = new Moq.Mock<IBar>(); 
barMock1.Setup(m=>m.ContextType).Returns(ContextType.Site); 

var barMock2 = new Moq.Mock<IBar>(); 
barMock2.Setup(m=>m.ContextType).Returns(ContextType.Local); 

var bar1Mock3 = new Moq.Mock<IBar>(); 
barMock3.Setup(m=>m.ContextType).Returns(ContextType.Test); 

_kernel.Bind<IBar>().ToMethod(s => barMock1.Object); 
_kernel.Bind<IBar>().ToMethod(s => barMock2.Object); 
_kernel.Bind<IBar>().ToMethod(s => barMock3.Object); 

這應該或多或少簡單的對象,但如果在伊巴爾依賴我們必須解決手動和使用ninject這是可取的。那麼更好的想法是如何獲得不同的對象嘲諷或某種方式來設置'範圍'?