1

The C# class that I wish to test accepts IEnumerable instances of the same interface. I use Ninject for dependency injection. How would I inject mocks into the IEnumerable using 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
}

This is how my regular binding looks like

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

Setting up mocks like below injects only the last mock into Foo (as supposed to injecting 3 mocks)

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

Any help is appreciated. Thanks

JRT
  • 11
  • 1
  • 4
  • When binding twice to same interface, you are actually _overriding_ previous binding, not adding a new one. So in fact, "Bar3" type will be instantiated, when resolving "IBar" anywhere in code. Can you explain more clearly, what are you trying to achieve? – Yura Apr 02 '15 at 18:54
  • I have a strategy pattern implemented with IBar's ContextType property as the key. So, I inject multiple strategies (Bars) into Foo and would like to inject mocks for each strategy during testing. – JRT Apr 02 '15 at 19:18

3 Answers3

0

Why don't just instantiate Foo by hand, if you are Unit Testing it?

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

But if a understand you right, you want IEnumerable<IBar> bars to be filled by a Ninject? Then you need to bind actual collection using Ninject:

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

Or, try actually array of IBar instead of IEnumerable<IBar>, and leave your binding as is:

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

According to manual, this should work.

Update: Bind to actual mock instances, and after resolve IFoo as usual:

 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: Try this way

_kernel.Bind<IBar>().ToMethod( x => bar1Mock.Object); 
_kernel.Bind<IBar>().ToMethod( x => bar2Mock.Object);
_kernel.Bind<IBar>().ToMethod( x => bar3Mock.Object);
Yura
  • 2,013
  • 19
  • 25
  • I could just instantiate a new instance of Foo by hand, but I'd like Ninject to handle that. Also ironically instantiating a new Foo by hand by passing in the array of barMock.Objects 1, 2 and 3 - didn't work. All three were of the last Test type – JRT Apr 02 '15 at 19:58
  • Any success with `IBar[] bars` constructor? – Yura Apr 02 '15 at 19:59
  • I can use ninject to inject non-mock Bar1, Bar2 and Bar3. No problem there, but I need to inject 3 mockBars – JRT Apr 02 '15 at 20:03
  • oh, i get it. Just change your setup. I have edited my answer. – Yura Apr 02 '15 at 20:09
  • The IEnumerable in Foo is injected with 3 mock Bar's, however they all refer to the last one - bar3Mock. So binding to same interface overriding previous binding, not adding a new one. – JRT Apr 02 '15 at 20:23
  • Lets try one more time. I have updated the answer. If you post some UT pet project - that will help significantly. – Yura Apr 02 '15 at 20:29
  • Using ToMethod() did not help. _kernel.Reset() did the trick. – JRT Apr 02 '15 at 20:39
0

I have this working now. _kernel needs to be reset before another unique mock of the same interface is requested. This code below works

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

Thanks

JRT
  • 11
  • 1
  • 4
0

Running into the same issue. Answers above didn't help. Here is one solution bellow, but it is not ideal.

Using kernel.Reset(); does not seem right.

Code like

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

Still returns link to the same (last) mock. Maybe I'm missing something?

I do want to use mocking kernel, but so far the best I got is:

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

This should work for more or less simple objects, but if there are dependencies in Ibar we'll have to resolve the manually and using ninject for that would be desirable. So any better ideas how to get different objects mocks or some way to set 'scope'?

Sergey Novikov
  • 644
  • 1
  • 4
  • 14