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

时间:2012-02-12 22:40:22

标签: 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)
                              );

但是Windsor抛出一个Castle.MicroKernel.ComponentRegistrationException,并显示消息“已经存在一个具有该名称的组件。”

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

<小时/> 根据{{​​3}},Castle Windsor 3允许注册覆盖,但我只能找到一个例子:

Container.Register(
    Classes.FromThisAssembly()
        .BasedOn<IEmptyService>()
        .WithService.Base()
        .ConfigureFor<EmptyServiceA>(c => c.IsDefault()));

ConfigureForBasedOnDescriptor类的方法。在我的情况下,我没有使用FromDescriptorBasedOnDescriptor

2 个答案:

答案 0 :(得分:63)

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

  1. 为其指定一个唯一名称
  2. 调用IsDefault方法
  3. 为了让这个例子起作用:

    this.WindsorContainer.Register(
                                 Component.For<IMediaPlayerProxyFactory>()
                                          .Instance(mockMediaPlayerProxyFactory)
                                          .IsDefault()
                                          .Named("OverridingFactory")
                              );
    

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

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

    现在可以将示例简化为:

    this.WindsorContainer.Register(
                                 Component.For<IMediaPlayerProxyFactory>()
                                          .Instance(mockMediaPlayerProxyFactory)
                                          .OverridesExistingRegistration()
                              );
    

    <小时/> 稍后修改

    3.1版引入了IsFallback方法。如果我使用IsFallback注册所有初始组件,则任何新注册都将自动覆盖这些初始注册。如果功能在当时可用,我会走这条路。

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

答案 1 :(得分:1)

不要在测试中重复使用容器。相反,请在null中将其设置为TearDown(),并为每次实际测试重新初始化。