使用Ninject MockingKernel Moq如何为同一个接口注入多个模拟

时间:2015-04-02 18:41:30

标签: c# unit-testing ninject moq ninject-mockingkernel

我想测试的C#类接受同一接口的IEnumerable实例。我使用Ninject进行依赖注入。我如何使用Ninject MockingKernel Moq

将注释注入IEnumerable
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
}

这是我的常规绑定看起来像

//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

设置像下面这样的模拟只会将最后一个模拟注入Foo(因为应该注入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>();

感谢任何帮助。感谢

3 个答案:

答案 0 :(得分: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 });

但如果你理解正确,你想要{Ninject填充IEnumerable<IBar> bars吗? 然后你需要使用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);

答案 1 :(得分: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);

由于

答案 2 :(得分: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);

这应该适用于或多或少的简单对象,但如果Ibar中存在依赖关系,我们必须手动解决并使用ninject,这是可取的。所以任何更好的想法如何获得不同的对象模拟或某种方式来设置范围&#39 ;?