1

我希望测试的 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>();

任何帮助表示赞赏。谢谢

4

3 回答 3

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);

谢谢

于 2015-04-02T20:38:30.460 回答
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 绑定实际的集合:

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

或者,尝试实际使用 array ofIBar而不是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);
    }
}

根据手册,这应该有效。

更新:绑定到实际的模拟实例,并像往常一样解析 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>();

更新2:试试这种方式

_kernel.Bind<IBar>().ToMethod( x => bar1Mock.Object); 
_kernel.Bind<IBar>().ToMethod( x => bar2Mock.Object);
_kernel.Bind<IBar>().ToMethod( x => bar3Mock.Object);
于 2015-04-02T19:33:01.530 回答
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 。那么任何更好的想法如何获得不同的对象模拟或某种方式来设置“范围”?

于 2015-08-07T14:29:55.827 回答