I want to do some integration testing using Simple Injector. However, sometimes I need to check whether a specific internal service has been called with the correct arguments. I am already using FakeItEasy in the test project, so my approach was to do this:
container.Options.RegisterResolveInterceptor(
(context, producer) =>
{
// this is the instance as it was provided by the container
object instance = producer();
object spy = FakeItEasy.Sdk.Create.Fake(context.Producer.ServiceType, options => options.Wrapping(instance));
Register(context.Producer.ServiceType, spy);
return spy;
});
While Register(...) keeps track of spies so that I can look the spy up after the invocation and do the required check later.
But I learnt, this only intercepts the directly resolved instances, not the implicitly created dependent instances. So I checked out the Interception Extensions of Simple Injector. But these snippets still rely on RealProxy and I didn't manage to make it .NET Core compliant using DispatchProxy, probably just because of my lack of deep experience with expression tree manipulation.
Then I found this answer and the ApplyInterceptor snippet, but while this approach seems promising, I am struggling to adapt the snippet so that the interceptor not just gets the factory method, but also gets to know the resolved service type:
container.Options.ApplyInterceptor(
factory =>
{
object instance = factory();
object spy = FakeItEasy.Sdk.Create.Fake(howToGetTheServiceType, options => options.Wrapping(instance));
Register(howToGetTheServiceType, spy);
return instance;
});
Any other suggestions?
The
ApplyInterceptorextension method from the documentation makes use of theExpressionBuildingevent. This event is unsuited for interception. Although it allows you to replace the constructed instance with another and even change types, the post condition is that the returned type must be the same implementation type of a sub type of the implementation.For instance, when a
Register<ILogger, ConsoleLogger>()registration is made, anExpressionBuildinghandler may replace the expression for something that returnsConsoleLoggerorConsoleLoggerSubClass : ConsoleLogger, but never for aFileLogger : ILogger.For your quest, you need to use the
ExpressionBuiltevent instead, as this is allowed to replaceConsoleLoggerwith aFileLogger.The following snippet, hopefully, gets you started: