Простой Инжектор, не может отменить существующую регистрацию
Я в настоящее время использую Simple Injector впервые. В моем проекте.NET я запускаю тестовые и фиктивные данные, возвращаемые веб-службой, и регистрирую объект в контейнере, как показано ниже.
_container.Register<IWebServiceOrder>(() => mock.Object, Lifestyle.Transient);
Это отлично работает. Но в моих тестах я хочу протестировать поведение системы при повторном обращении к веб-службе, которая будет содержать обновленные данные, поэтому фиктивный объект необходимо будет обновить.
По умолчанию Simple Injector не позволяет переопределять существующие регистрации, но официальный сайт заявляет, что можно изменить это поведение, как показано ниже.
https://simpleinjector.readthedocs.org/en/latest/howto.html
container.Options.AllowOverridingRegistrations = true;
К сожалению, я все еще получаю ошибку, когда я пытаюсь зарегистрировать объект во второй раз, даже с приведенным выше кодом.
Контейнер нельзя изменить после первого вызова GetInstance, GetAllInstances и Verify
Любые идеи о том, почему это происходит?
1 ответ
Замена существующей регистрации после того, как вы уже работали с контейнером, вряд ли когда-либо будет работать так, как вы ожидаете (и это относится ко всем библиотекам DI), и именно поэтому контейнер Simple Injector заблокирован. Это описано более подробно здесь (как уже указывалось @qujck).
Прежде всего, если вы пишете модульные тесты, вам вообще не следует использовать контейнер. Ваши модульные тесты должны сами создавать тестируемый класс, или вы извлекаете эту логику в удобный фабричный метод, такой как:
private static MailNotifier CreateMailNotifier(
IDeposit deposit = null, ISendMail mailSender = null, ILog logger = null)
{
return new MailNotifier(
deposit ?? Substitute.For<IDeposit>(),
mailSender ?? Substitute.For<ISendMail>(),
logger ?? Substitute.For<ILog>());
}
Этот фабричный метод является вариацией шаблона Test Data Builder.
Используя необязательные параметры, он позволяет модульному тесту указывать только ложную реализацию, которая требуется во время тестирования:
public void Notify_WithValidUser_LogsAMessage()
{
// Arrange
var user = new User();
var logger = new FakeLogger();
MailNotifier sut = CreateMailNotifier(logger: logger);
// Act
sut.Notify(user);
// Assert
Assert.AreEqual(expected: 1, actual: logger.LoggedMessages.Count);
}
Если вы используете контейнер, потому что создание тестируемого класса вручную слишком громоздко, это указывает на проблему в тестируемом классе (скорее всего, нарушение принципа единой ответственности). Не используйте инструменты для решения проблем в вашем дизайне; ваш код говорит с вами.
Для интеграционных тестов, однако, гораздо более обычно использовать контейнер, но в этом случае вы должны просто создать новый контейнер для каждого интеграционного теста. Таким образом, вы можете добавить или заменить IWebServiceOrder
без каких-либо проблем.