在Castle Windsor 3中,覆盖单元测试中的现有组件注册

And*_*erd 27 unit-testing castle-windsor

我试图在我的自动化测试中使用Castle Windsor,如下所示:

每次测试:

  • Setup()函数创建一个Windsor容器,注册每个组件的默认实现
  • Test函数通过该方法访问组件IWindsorContainer.Resolve<T>,并测试它们的行为
  • TearDown()函数处理Windsor容器(以及任何创建的组件)

例如,我可能有15个测试访问组件,这些组件间接导致组件的创建IMediaPlayerProxyFactory.该SetUp函数注册了一个足够好的实现IMediaPlayerProxyFactory,所以我没有在15个测试中的每个测试中注册这个的维护负担.

但是,我现在正在编写测试Test_MediaPlayerProxyFactoryThrowsException,确认我的系统优雅地处理IMediaPlayerProxyFactory组件中的错误.在测试方法中,我创建了我的特殊模拟实现,现在我想将它注入到框架中:

this.WindsorContainer.Register(
                                 Component.For<IMediaPlayerProxyFactory>()
                                          .Instance(mockMediaPlayerProxyFactory)
                              );
Run Code Online (Sandbox Code Playgroud)

但温莎抛出一条Castle.MicroKernel.ComponentRegistrationException消息,"已经有一个有这个名字的组件."

有什么方法可以让我mockMediaPlayerProxyFactory成为默认实例IMediaPlayerProxyFactory,丢弃已经注册的组件?


根据文档,Castle Windsor 3允许注册覆盖,但我只能找到一个例子:

Container.Register(
    Classes.FromThisAssembly()
        .BasedOn<IEmptyService>()
        .WithService.Base()
        .ConfigureFor<EmptyServiceA>(c => c.IsDefault()));
Run Code Online (Sandbox Code Playgroud)

ConfigureFor是一种BasedOnDescriptor类的方法.在我的情况下,我没有使用FromDescriptorBasedOnDescriptor.

And*_*erd 66

要创建覆盖实例,您需要做两件事:

  1. 为其指定一个唯一的名称
  2. 调用IsDefault方法

为了让这个例子起作用:

this.WindsorContainer.Register(
                             Component.For<IMediaPlayerProxyFactory>()
                                      .Instance(mockMediaPlayerProxyFactory)
                                      .IsDefault()
                                      .Named("OverridingFactory")
                          );
Run Code Online (Sandbox Code Playgroud)

因为我计划在许多测试中使用这个覆盖模式,所以我创建了自己的扩展方法:

public static class TestWindsorExtensions
{
    public static ComponentRegistration<T> OverridesExistingRegistration<T>(this ComponentRegistration<T> componentRegistration) where T : class
    {
        return componentRegistration
                            .Named(Guid.NewGuid().ToString())
                            .IsDefault();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,该示例可以简化为:

this.WindsorContainer.Register(
                             Component.For<IMediaPlayerProxyFactory>()
                                      .Instance(mockMediaPlayerProxyFactory)
                                      .OverridesExistingRegistration()
                          );
Run Code Online (Sandbox Code Playgroud)


稍后编辑

3.1版介绍了该IsFallback方法.如果我注册了所有初始组件IsFallback,那么任何新注册都将自动覆盖这些初始注册.如果功能在当时可用,我会走这条路.

https://github.com/castleproject/Windsor/blob/master/docs/whats-new-3.1.md#fallback-components

  • 感谢您更新答案. (2认同)