我试图在我的自动化测试中使用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()));
ConfigureFor
是BasedOnDescriptor
类的方法。在我的情况下,我没有使用FromDescriptor
或BasedOnDescriptor
。
答案 0 :(得分:63)
创建覆盖实例需要做两件事:
IsDefault
方法为了让这个例子起作用:
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()
,并为每次实际测试重新初始化。