Simple Injector,无法覆盖现有注册

use*_*155 6 c# simple-injector

我目前第一次使用Simple Injector.在我的.NET项目中,我正在运行测试和模拟从Web服务返回的数据并将对象注册到容器中

 _container.Register<IWebServiceOrder>(() => mock.Object, Lifestyle.Transient);
Run Code Online (Sandbox Code Playgroud)

这很好用.但在我的测试中,我想在第二次调用包含更新数据的Web服务时测试系统的行为,因此需要更新模拟对象.

默认情况下,Simple Injector不允许覆盖现有注册,但官方网站声明可以更改此行为,如下所示.

https://simpleinjector.readthedocs.org/en/latest/howto.html#override-existing-registrations

container.Options.AllowOverridingRegistrations = true;
Run Code Online (Sandbox Code Playgroud)

不幸的是,当我尝试第二次注册对象时,即使使用上面的代码,我仍然会收到错误.

首次调用GetInstance,GetAllInstances和Verify后,无法更改容器

有关为什么会发生这种情况的任何想法?

Ste*_*ven 9

在您使用容器之后更换现有注册几乎没有您期望的行为(这适用于所有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>());
}
Run Code Online (Sandbox Code Playgroud)

此工厂方法是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);
}
Run Code Online (Sandbox Code Playgroud)

如果您使用容器,因为手动创建受测试的类太麻烦,它表示您所测试的类中存在问题(很可能是单一责任原则违规).防止使用工具解决设计中的问题; 你的代码正在跟你说话.

但是,对于集成测试,使用容器更常见,但在这种情况下,您应该为每个集成测试创建一个新容器.这样您就可以添加或替换IWebServiceOrder没有任何问题.