Reputation: 1122
I have encountered a problem while using Moq (v4.8.1) in a factory method for Castle.Windsor (v4.1.0). I would like to know if anyone else has encountered this, and what they did to solve it.
I have a simple interface defined as:
interface IFoo
{
Task DoFooAsync(Bar bar);
}
In my main project I register the following in my WindsorContainer:
container
.Register(Component.For<IFoo, Foo>()
.LifestyleTransient());
This resolves nicely at runtime.
In my test project I do the following:
container.Register(Component.For<IFoo>().UsingFactorymethod(() => {
var mock = new Mock<IFoo>();
mock
.Setup(x => x.DoFooAsync(It.IsAny<Bar>()))
.Returns(() => Task.FromResult(true));
return mock.Object;
})
.IsDefault());
This fails during test with the message from Castle.MicroKernel.ComponentActivator.AbstractComponentActivator.ApplyCommissionConcerns(Object instance):
"Can not apply commission concerns to component Late Bound MyAssembly.IFoo because it appears to be a target-less proxy. Currently those are not supported."
Note: The 'IsDefault()' is only there to make Castle.Windsor override the registration from the main project, and it is not related to this problem (I tried running without it and the problem persists).
If I instead do the following:
// exact same code as above, just placed outside the factory method
var mock = new Mock<IFoo>();
mock
.Setup(x => x.DoFooAsync(It.IsAny<Bar>()))
.Returns(() => Task.FromResult(true));
// different registration
container
.Register(Component.For<IFoo>()
.Instance(mock.Object).IsDefault());
Then everything works. But now my IFoo instance is reused each time IFoo is resolved - which is a different behavior than in my main project, and therfore not desired.
I have looked into the Castle.Windsor code to understand what is going on, but without real success.
Upvotes: 1
Views: 849
Reputation: 7
This works for me. UsingFactoryMethod()
was failing. It uses Nsubstitute for fake injection.
var blobservice = Substitute.For<IBlobFileService>();
RegisterFakeServiceInstance(blobservice);
private void RegisterFakeServiceInstance<TService>(TService fakeService) where TService : class
{
IocManager.IocContainer.Register(
Component.For<TService>()
.Instance(fakeService)
.LifestyleSingleton()
);
}
Upvotes: 0
Reputation: 4408
Moq internally uses Castle's dynamic proxy and mocked class is in fact proxy generated by Castle and that's what for some internal reasons Castle's developers don't want to support. You can read about it more here:
https://github.com/castleproject/Windsor/issues/224
https://github.com/castleproject/castle-youtrack-export/blob/master/IOC/IOC-332.xml
So as Nkosi already commented, you should rather think about what you really need to achieve and reconsider your design.
Upvotes: 1
Reputation: 2407
"my IFoo instance is reused each time IFoo is resolved - which is a different behavior than in my main project, and therfore not desired."
What about creating a property with a lambda? Something like:
private IFoo TheMock => CreateMock();
private IFoo CreateMock()
{
var mock = new Mock<IFoo>();
mock
.Setup(x => x.DoFooAsync(It.IsAny<Bar>()))
.Returns(() => Task.FromResult(true));
return mock.Object;
}
And then register it
container
.Register(Component.For<IFoo>()
.Instance(TheMock).IsDefault());
Disclaimer: Haven't tested that, because I do not use Castle.Windsor.
Upvotes: 0