Я хочу провести интеграционное тестирование с помощью Simple Injector. Однако иногда мне нужно проверить, была ли вызвана конкретная внутренняя служба с правильными аргументами. Я уже использую FakeItEasy в тестовом проекте, поэтому мой подход заключался в следующем:
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;
});
Пока Register(...)
отслеживает шпионов, чтобы я мог найти шпиона после вызова и выполнить необходимую проверку позже.
Но я узнал, что это перехватывает только экземпляры с прямым разрешением, а не неявно созданные зависимые экземпляры. Итак, я проверил Расширения для перехвата Simple Injector. Но эти фрагменты по-прежнему полагаются на RealProxy
, и мне не удалось сделать их совместимыми с .NET Core с помощью DispatchProxy
, вероятно, просто из-за отсутствия у меня глубокого опыта работы с деревом выражений.
Затем я нашел этот ответ и сниппет ApplyInterceptor
, но хотя этот подход кажется многообещающим, я изо всех сил пытаюсь адаптировать сниппет, чтобы перехватчик не просто получал фабричный метод, но и узнавал разрешенный тип службы:
container.Options.ApplyInterceptor(
factory =>
{
object instance = factory();
object spy = FakeItEasy.Sdk.Create.Fake(howToGetTheServiceType, options => options.Wrapping(instance));
Register(howToGetTheServiceType, spy);
return instance;
});
Любые другие предложения?
Метод расширения ApplyInterceptor
из документации использует событие ExpressionBuilding
. Это событие не подходит для перехвата. Хотя он позволяет заменить сконструированный экземпляр другим и даже изменить типы, пост-условие заключается в том, что возвращаемый тип должен быть тем же типом реализации, что и подтип реализации.
Например, при регистрации Register<ILogger, ConsoleLogger>()
обработчик ExpressionBuilding
может заменить выражение на что-то, что возвращает ConsoleLogger
или ConsoleLoggerSubClass : ConsoleLogger
, но никогда на FileLogger : ILogger
.
Вместо этого для вашего квеста вам нужно использовать событие ExpressionBuilt
, так как это позволяет заменить ConsoleLogger
на FileLogger
.
Следующий фрагмент, надеюсь, поможет вам начать:
container.ExpressionBuilt += (s, e) =>
{
// Compile the original object creation into a delegate.
var factory =
(Func<object>)Expression.Lambda(typeof(Func<object>), e.Expression).Compile();
// Create a registration for the spy, based on the original lifestyle
var spyregistration = e.Lifestyle.CreateRegistration(
e.RegisteredServiceType,
() =>
{
var instance = factory();
var spy = FakeItEasy.Sdk.Create
.Fake(e.RegisteredServiceType, options => options.Wrapping(instance));
RegisterSpy(e.RegisteredServiceType, spy);
return spy;
},
container);
// Replace expression of the registration with the spy registration.
e.Expression = spyregistration.BuildExpression();
};
Спасибо, это работает! Сейчас изучаю какие сервисы ломают подмену лисков: видимо много