Mocking a connection to a data source inside a function with Moq? - c#

I'm starting to use Moq and I cannot figure out how to test the method Execute in the code below:
I have the following class:
public class MyObject {
private IDataReaderPlugin m_source;
private IDataWriterPlugin m_dest;
private string[] m_dummyTags = new string[] { "tag1", "tag2", "tag3"};
public void Execute(DateTime time)
{
DataCollection tags = m_source.SnapshotUtc(m_dummyTags, time);
//Doing some treatment on the values in tags
m_dest.Write(tags);
}
}
Another method is responsible to create and initialize IDataReaderPlugin and IDataWriterPlugin from information in a configuration file.
I want to test the method Execute. So, I need to mock m_source and m_dest and after I want to test the result sent to m_dest.
How I can achieve this with Moq?
Thanks.

[Test]
public void ShouldWriteToMDest()
{
// Arrange
var mockDest = new Mock<IDataWriterPlugin>();
var mockSource = new Mock<IDataReaderPlugin>();
string[] m_dummyTags = new string[] { "tag1", "tag2", "tag3"};
mockSource.Setup(source => source.SnapshotUtc(m_dummyTags, It.IsAny<DateTime>()).Returns(/*whatever you need*/);
var myObj = new MyObject(mockSource.Object, mockDest.Object);
// Act
myObj.Execute(DateTime.Now);
// Assert
Assert.That(mockSource.Object.WhateverPropertyContainsOutput == /*Whatever you need */);
}

This should get you started:
DateTime myDate = DateTime.Now;
DataCollection tags = new DataCollection();
Mock<IDataReaderPlugin> dataReaderPlugin = new Mock<IDataWriterPlugin>();
dataReaderPlugin.Setup(drp => drp.SnapshotUtc(It.IsAny<string[]>(), myDate)).Returns(tags);
Mock<IDataWriterPlugin> dataWriterPlugin = new Mock<IDataWriterPlugin>();
dataWriterPlugin.Setup(dwp => dwp.Write(tags);
MyObject mo = new MyObject();
mo.Execute();
mock.Verify(foo => foo.Write(tags));

"Another method is responsible" - this is the crucial bit of information. If you are using an IoC or DI framework then you'll need to insert some Moq mocks of the interfaces IDataReaderPlugin and IDataWriterPlugin. Then the Execute method will use these mocks supplied by the IoC/DI framework.
If they are simply set by a setter or property then it's as simple as:
// Arrange
var mo = new MyObject();
var srcMock = new Mock<IDataReaderPlugin>();
src.Setup(src => src.SnapshotUtc(It.IsAny<string[]>(), It.IsAny<DateTime>()))
.Returns(new DataCollection() /* or whatever */);
mo.SetSource(srcMock.Object);
// ... same for m_dest
// Act
mo.Execute(DateTime.Now);
// Assert
// assert something... srcMock.Verify() or whatever

Related

Failed to register Instance in AutoFac?

I want to use the existing mock instance of my project in AutoFac. I do not want to rewrite my PROD code. So I found something AutoFac which is not working. I think I am missing something.
I have tried below code.
public AboutTideEditorMockTest () {
aboutTideService = new AboutTideEditorService (iAboutTideEditorRepository.Object, exceptionLogServiceMock.Object);
aboutTideServiceWithNullParam = new AboutTideEditorService (null, exceptionLogServiceMock.Object);
}
//This is my test case
[FactWithAutomaticDisplayName]
public void Test1 () {
var cb = new ContainerBuilder ();
var studyLoaderMock = new Mock<IAboutTideEditorService> ().Object;
var studyLoaderMock1 = iAboutTideEditorRepository.Object;
var studyLoaderMock2 = exceptionLogServiceMock.Object;
cb.RegisterInstance (studyLoaderMock).As<IAboutTideEditorService> ();
cb.RegisterInstance (studyLoaderMock1).As<IAboutTideEditorRepository> ();
cb.RegisterInstance (studyLoaderMock2).As<IExceptionLogService> ();
var container = cb.Build ();
using (var scope = container.BeginLifetimeScope ()) {
var component = scope.Resolve<AboutTideEditorService> ();
responseData = component.AddAboutTideContent (applicationUser, aboutTide);
Assert.Equal (ProcessStatusEnum.Invalid, responseData.Status);
}
}
I want to use the existing mock instance that I am passing to "RegisterInstance". When I am trying to debug my test case I am getting "responseData" null. I am not able to go inside in AddAboutTideContent.
You are not setting up the mock return value and you need to resolve IAboutTideEditorService rather than AboutTideEditorService.
You also need to generate the mocks differently. There is no need to change the production code though!
Do it like this:
[FactWithAutomaticDisplayName]
public void Test1() {
var cb = new ContainerBuilder();
var studyLoaderMock = new Mock<IAboutTideEditorService>();
var studyLoaderMock1 = new Mock<IAboutTideEditorRepository>(); // you don't need that when resolving only IAboutTideEditorService
var studyLoaderMock2 = new Mock<IExceptionLogService>(); // you don't need that when resolving only IAboutTideEditorService
cb.RegisterInstance(studyLoaderMock.Object).As<IAboutTideEditorService>();
cb.RegisterInstance(studyLoaderMock1.Object).As<IAboutTideEditorRepository>(); // you don't need that when resolving only IAboutTideEditorService
cb.RegisterInstance(studyLoaderMock2.Object).As<IExceptionLogService>(); // you don't need that when resolving only IAboutTideEditorService
var container = cb.Build();
studyLoaderMock
.Setup(x => x.AddAboutTideContent(It.IsAny<YourTypeHereForParameterA>,
It.IsAny<YourTypeHereForParameterB>)
.Returns(new MyResponseDataType()); // add the right types here necessary, I can't tell which types they are because I am not seeing the functions code
using (var scope = container.BeginLifetimeScope()) {
var component = scope.Resolve<IAboutTideEditorService>(); // changed to IAboutTideEditorService
responseData = component.AddAboutTideContent(applicationUser, aboutTide);
Assert.Equal(ProcessStatusEnum.Invalid, responseData.Status);
}
}
Your function call was returning null because that's the default behavior of a mock with Moq = MockBehavior.Loose. If you want a function of a mock to return a specific value for non explicit or explicit parameters, you have to call Setup(delegate) and Returns(objectInstance) or Returns(Func<ObjectType>).
In general your test-setup doesn't make much sense. You are basically only registering mocks with the Autofac-Container which makes the container itself irrelevant for your tests. Using IoC for tests is usually only required when you are directly testing against the implementations rather than mocks. Those tests are called Integration-Tests.
It would make more sense like this:
[FactWithAutomaticDisplayName]
public void Test1() {
var cb = new ContainerBuilder();
var studyLoaderMock1 = new Mock<IAboutTideEditorRepository>();that when resolving only IAboutTideEditorService
var studyLoaderMock2 = new Mock<IExceptionLogService>();
var studyLoader = new AboutTideEditorService(studyLoaderMock1.Object, studyLoaderMock2.Object);
cb.RegisterInstance(studyLoader).As<IAboutTideEditorService>();
var container = cb.Build();
// now setup the functions of studyLoaderMock1 and studyLoaderMock2
// required for your function `AddAboutTideContent` from `IAboutTideEditorService` to work.
using (var scope = container.BeginLifetimeScope()) {
var component = scope.Resolve<IAboutTideEditorService>(); // changed to IAboutTideEditorService
responseData = component.AddAboutTideContent(applicationUser, aboutTide);
Assert.Equal(ProcessStatusEnum.Invalid, responseData.Status);
}
}
Keep in mind that I am assuming here the order of the parameters required for AboutTideEditorService. For more information on how to setup mocks with Moq take a look here.

Testing HttpModule wtih Response.Filter and Response.Write

I'm working on an Http Module that simply records the response time and size and then appends the results to the response body.
My module looks something like this:
public override void PreRequestHandlerExecute(HttpContextBase context)
{
// Add a filter to capture response stream
context.Response.Filter = new ResponseSniffer(context.Response.Filter);
}
public override void ApplicationEndRequest(HttpContextBase context)
{
....
context.Response.Write(builder.ToString());
}
I now wish to unit test this module. I'm very new to unit testing. I've adapted code from o2platform to get a moq httpcontext and that works so far. However, the response filter does seem to get set in Pre and the response body is what I initialized it has from the test setup.
I've tried a handful options (and read a lot of stuff) but none of these seemed to work:
public Mock<HttpResponseBase> MockResponse { get; set; }
...
var outputStream = new MemoryStream();
var filter = new MemoryStream();
//MockResponse.Setup(response => response.OutputStream).Returns(GetMockStream(outputStream).Object);
//MockResponse.Setup(response => response.Filter).Returns(GetMockStream(filter).Object);
MockResponse.Setup(response => response.OutputStream).Returns(() => outputStream);
//MockResponse.SetupSet(response => response.OutputStream = It.IsAny<Stream>()).Returns(() => outputStream);
MockResponse.Setup(response => response.Filter).Returns(() => filter);
MockResponse.SetupSet(response => response.Filter = It.IsAny<Stream>());
MockResponse.SetupSet(response => response.Filter = It.IsAny<ResponseSniffer>());
Test Method
[TestMethod]
public void TestMethod1()
{
var mockHttpContext = new MoqHttpContext();
var httpContext = mockHttpContext.HttpContext();
var html = #"<html>
<head></head>
<body>
<h1>Hello World</h1>
</body>
</html>";
httpContext.ResponseWrite(html);
httpContext.StreamWrite(httpContext.Response.Filter, html);
var module = new Module();
module.PreRequestHandlerExecute(mockHttpContext.HttpContext());
module.ApplicationBeginRequest(mockHttpContext.HttpContext());
module.ApplicationEndRequest(mockHttpContext.HttpContext());
var responseRead = httpContext.ResponseRead(); //extension method to get output stream
var b = 1; //put breakpoint here
}
I realize the test needs to Assert rather then the breakpoint. I also realize that the test should be broken up a bit.
Code Repo
Github
Let's see at the following statement in Module.ApplicationEndRequest() method:
context.Response.Write(builder.ToString());
When this code is executed from Unit Test, context.Response is a mock that you set up in MoqHttpContext.CreateBaseMocks():
MockResponse = new Mock<HttpResponseBase>();
// ...
MockContext.Setup(ctx => ctx.Response).Returns(MockResponse.Object);
You can't expect that you call a Write() method on a mock and then can read the same data back. Mock is a fake object. Its default implementation of Write() method does nothing, and passed data is just lost.
To fix the problem, you could setup a callback on Response mock that will write passed data to a stream and then return it back on read. You are actually very close to it.
In MoqHttpContext class declare a stream where you will save the data:
public class MoqHttpContext
{
private readonly MemoryStream _outputStream = new MemoryStream();
// ...
}
Then in CreateBaseMocks() method setup a callback:
public MoqHttpContext CreateBaseMocks()
{
// ...
MockResponse = new Mock<HttpResponseBase>();
MockResponse.Setup(x => x.Write(It.IsAny<string>())).Callback<string>(s =>
{
var data = Encoding.ASCII.GetBytes(s);
_outputStream.Write(data, 0, data.Length);
_outputStream.Flush();
_outputStream.Position = 0;
});
// ...
}
You also should remove a line that sets inputStream position to 0 in MoqHttpContextExtensions.StreamWrite(), so that html data that you write in UnitTest1.TestMethod1() is appended, not overwritten:
public static HttpContextBase StreamWrite(this HttpContextBase httpContextBase, Stream inputStream, string text)
{
if (inputStream == null) inputStream = new MemoryStream();
var streamWriter = new StreamWriter(inputStream);
inputStream.Position = inputStream.Length;
streamWriter.Write(text);
streamWriter.Flush();
// Remove this line
//inputStream.Position = 0;
return httpContextBase;
}
That's it. Now if you check value of responseRead in the test, you will see that data appended by Http module is there.
UPDATE (Fixing problem with a filter)
There are 3 different issues with current code that prevent correct work of a filter from UT.
You tried handful options for mocking Filter property, however none of them seems correct. The correct way to mock property getter with Moq is:
MockResponse.SetupGet(response => response.Filter).Returns(filter);
Remove all other statements for mocking response.Filter, but don't add above statement yet, it's not a final version.
You have following check in Module.ApplicationEndRequest() method:
if (context.Response.Filter is ResponseSniffer filter)
{
// ...
When UT is executed, context.Response.Filter is a MemoryStream not a ResponseSniffer. Setter that is called in Module constructor:
context.Response.Filter = new ResponseSniffer(context.Response.Filter);
will not actually affect value returned by Filter getter because it's a mock that currently always return instance of MemoryStream that you setup with SetupGet. To fix this problem you should actually emulate property behavior: save the value passed to setter and return it in the getter. Here is a final setup of response.Filter property:
Stream filter = new MemoryStream();
MockResponse.SetupSet(response => response.Filter = It.IsAny<Stream>()).Callback<Stream>(value => filter = value);
MockResponse.SetupGet(response => response.Filter).Returns(() => filter);
Make sure you have deleted all other mocks of response.Filter property.
The final problem that you should fix - is the order of Module invocations from UT. Currently the order is the following:
httpContext.StreamWrite(httpContext.Response.Filter, html);
// ...
var module = new Module();
module.PreRequestHandlerExecute(mockHttpContext.HttpContext());
But PreRequestHandlerExecute sets Response.Filter with an instance of ResponseSniffer. So when httpContext.StreamWrite above it is called, httpContext.Response.Filter holds actually instance of MemoryStream, not ResponseSniffer. So the last fix you should make is to change the order of statements in UT body:
// ...
var module = new Module();
module.PreRequestHandlerExecute(mockHttpContext.HttpContext());
httpContext.ResponseWrite(html);
httpContext.StreamWrite(httpContext.Response.Filter, html);
module.ApplicationBeginRequest(mockHttpContext.HttpContext());
module.ApplicationEndRequest(mockHttpContext.HttpContext());
// ...
UPDATE (UT Redesign)
At this point your UT should work. However current test is very cumbersome. The fact that it takes so much time to understand why it does not work proves it. Such tests are very hard to maintain and fix, they become a real pain over time.
Moreover it's rather Integration test than Unit test, because it invokes several of classes with different functionality - ResponseSniffer and Module.
You should strongly consider redesign of current test. And the good start is to make separate tests for ResponseSniffer and Module classes.
Most valuable test for ResponseSniffer is the one that verifies that written data is registered in RecordStream:
[TestClass]
public class ResponseSnifferTests
{
[TestMethod]
public void Write_WritesDataToRecordStream()
{
// Arrange
var inData = new byte[] { 0x01 };
var target = new ResponseSniffer(Mock.Of<Stream>());
// Act
target.Write(inData, 0, inData.Length);
// Assert
target.RecordStream.Position = 0;
var outData = new byte[inData.Length];
int outSize = target.RecordStream.Read(outData, 0, outData.Length);
Assert.AreEqual(inData.Length, outSize);
CollectionAssert.AreEqual(inData, outData);
}
}
As regards Module class, there are several checks that should be made:
PreRequestHandlerExecute() sets Response.Filter with instance of ResponseSniffer.
ApplicationBeginRequest() adds Stopwatch to context.Items dictionary.
ApplicationEndRequest() writes request info to the response.
UT approach implies checking of these facts in separate tests. Here are samples of such 3 tests:
[TestClass]
public class ModuleTests
{
[TestMethod]
public void PreRequestHandlerExecuteShouldSetResponseSnifferAsFilter()
{
// Arrange
Stream filter = null;
Mock<HttpResponseBase> httpResponseMock = new Mock<HttpResponseBase>();
httpResponseMock.SetupSet(response => response.Filter = It.IsAny<Stream>()).Callback<Stream>(value => filter = value);
Mock<HttpContextBase> httpContextStub = new Mock<HttpContextBase>();
httpContextStub.SetupGet(x => x.Response).Returns(httpResponseMock.Object);
var target = new Module();
// Act
target.PreRequestHandlerExecute(httpContextStub.Object);
// Assert
Assert.IsNotNull(filter);
Assert.IsInstanceOfType(filter, typeof(ResponseSniffer));
}
[TestMethod]
public void ApplicationBeginRequestShouldStoreStopwatchInContextItems()
{
// Arrange
var items = new Dictionary<string, object>();
Mock<HttpContextBase> httpContextStub = new Mock<HttpContextBase>();
httpContextStub.SetupGet(x => x.Items).Returns(items);
var target = new Module();
// Act
target.ApplicationBeginRequest(httpContextStub.Object);
// Assert
Assert.IsTrue(items.ContainsKey("X-ResponseTime"));
Assert.IsInstanceOfType(items["X-ResponseTime"], typeof(Stopwatch));
}
[TestMethod]
public void ApplicationEndRequestShouldAddRequestInfoToResponse()
{
// Arrange
Mock<HttpRequestBase> httpRequestMock = new Mock<HttpRequestBase>();
httpRequestMock.SetupGet(x => x.FilePath).Returns("/test");
string writtenData = null;
Mock<HttpResponseBase> httpResponseMock = new Mock<HttpResponseBase>();
httpResponseMock.Setup(x => x.Write(It.IsAny<string>())).Callback<string>(s => writtenData = s);
Mock<HttpContextBase> httpContextStub = new Mock<HttpContextBase>();
httpContextStub.SetupGet(x => x.Request).Returns(httpRequestMock.Object);
httpContextStub.SetupGet(x => x.Response).Returns(httpResponseMock.Object);
httpContextStub.SetupGet(x => x.Items).Returns(new Dictionary<string, object> { ["X-ResponseTime"] = new Stopwatch() });
var target = new Module();
// Act
target.ApplicationEndRequest(httpContextStub.Object);
// Assert
Assert.IsTrue(Regex.IsMatch(writtenData, #"Response Size: \d+ bytes<br/>"));
Assert.IsTrue(Regex.IsMatch(writtenData, #"Module request time: \d+ ms"));
}
}
As you see, the tests are pretty simple and straightforward. You don't need those MoqHttpContext and MoqHttpContextExtensions with a lot of mocks and helpers anymore. Another benefit - if some of the tests get broken, it's much easier to identify the root cause and fix it.
If you are new to Unit Testing and are looking for good source of info on it, I strongly suggest book The Art of Unit Testing by Roy Osherove.

How to write a test that tests that AutoMapper is called with the correct operation options

I have this piece of code and want to test that opts.Items["foo"] is set correctly.
public Result DoStuff(MyInput myObj)
{
var mapped = _mapper.Map<Result>(myObj,
opts =>
{
opts.Items["foo"] = "bar";
});
return mapped;
}
And my test looks like this
public void MapperShouldBeCalledWithCorrectOperationItems()
{
// Arrange
var optObj = Substitute.For<IMappingOperationOptions>();
Action<IMappingOperationOptions> argumentUsed = null;
_mapper.Received().Map<Result>(result, Arg.Do<Action<IMappingOperationOptions>>(arg => argumentUsed = arg));
// Act
_uut.DoStuff(new MyInput());
argumentUsed.Invoke(optObj);
// Assert
optObj.Items["foo"].Should().Be("bar");
}
Now this doesn't work and I'm not even sure I'm on the right path :(
I don't think I can inspect the lambda so I instead have to check that IMappingOperationOptions have Items["foo"] set.
Any suggestions?
I figured it out!
public void MapperShouldBeCalledWithCorrectOperationItems()
{
// Arrange
var optObj = Substitute.For<IMappingOperationOptions>();
Action<IMappingOperationOptions> argumentUsed = null;
_mapper
.Map<Result>(Arg.Any<Result>,
Arg.Do<Action<IMappingOperationOptions>>(arg => argumentUsed = arg));
// Act
_uut.DoStuff(new MyInput());
argumentUsed.Invoke(optObj);
// Assert
optObj.Items["foo"].Should().Be("bar");
}

How to UnitTest a Function in a mocked method

How can I test the DeleteAppointmentById here?
Func<IDataAdapterRW, IEnumerable<uint>> function = db => DeleteAppointmentById(db, appointmentId);
return _dataContextProvider.GetContextRW().Run(function);
_dataContextProvider is mocked with moq. If I run the test it never enters DeleteAppointmentById of course
The method to test:
public IEnumerable<uint> DeleteAppointment(uint appointmentId)
{
Func<IDataAdapterRW, IEnumerable<uint>> function = db => DeleteAppointmentById(db, appointmentId);
return _dataContextProvider.GetContextRW().Run(function);
}
DeleteAppointmentById is the inner method (private) I am really interested in.
my test:
[Test]
public void DeleteAppointment_Valid_DeletedRecordId()
{
//Setup
var dbContextMock = new Mock<IDataContextProvider>();
var dataAdapterMock = new Mock<IDataContext<IDataAdapterRW>>();
dbContextMock.Setup(d => d.GetContextRW())
.Returns(dataAdapterMock.Object);
dataAdapterMock.Setup(a => a.Run(It.IsAny<Action<IDataAdapterRW>>()));
var calendarService = new CalendarService(dbContextMock.Object);
//Run
var result = calendarService.DeleteAppointment(1);
//Assert
Assert.AreEqual(1, result);
}
You can access the result of the Func passed as parameter in Run method, and to Assert the result like below.
Why to return the result? Because it's a mock and don't know how Run method is behaving.
[Test]
public void DeleteAppointment_Valid_DeletedRecordId()
{
//Setup
var dbContextMock = new Mock<IDataContextProvider>();
var dataAdapterMock = new Mock<IDataContext<IDataAdapterRW>>();
dbContextMock.Setup(d => d.GetContextRW())
.Returns(dataAdapterMock.Object);
dataAdapterMock.Setup(a => a.Run(It.IsAny<Func<IDataAdapterRW, IEnumerable<uint>>>()))
.Returns((Func<IDataAdapterRW, IEnumerable<uint>> func) => { return func(dataAdapterMock.Object);}); // configure the mock to return the list
var calendarService = new CalendarService(dbContextMock.Object);
//Run
int id = 1;
var result = calendarService.DeleteAppointment(id);
//Assert
var isInList = result.Contains(id); // verify the result if contains the
Assert.AreEqual(isInList, true);
}
Unit tests tend to take the following structure:
Arrange: set up the context. In this case, you'd probably create an appointment and save it to the database.
Act: call the unit you're testing. In this case, DeleteAppointmentById(db, appointment).
Assert: check if side effects and returns were correct. In this case, you may attempt to load this appointment from the database, and assert that you were unable (because it should have been deleted).

Using Ninject MockingKernel Moq how to inject multiple mocks for the same interface

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

Categories