Reputation: 11
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
Upvotes: 1
Views: 2583
Reputation: 644
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'?
Upvotes: 0
Reputation: 11
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
Upvotes: 0
Reputation: 2421
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);
Upvotes: 0