2012-02-12 23 views
21

Estoy intentando utilizar el castillo de Windsor en mis pruebas automatizadas, así:En el castillo de Windsor 3, anular un registro de componentes existentes en una unidad de prueba

En cada prueba:

  • La función Setup() crea una recipiente Windsor, registrarse implementaciones predeterminadas de cada componente
  • el Test acceso a las funciones de los componentes mediante el método de IWindsorContainer.Resolve<T>, y pone a prueba su comportamiento
  • el TearDown() dispone de función del contenedor de Windsor (y cualquier componentes creados)

Por ejemplo, podría haber 15 pruebas que accede a los componentes que indirectamente como resultado la creación de un componente IMediaPlayerProxyFactory. La función SetUp registra una implementación lo suficientemente buena IMediaPlayerProxyFactory, por lo que no tengo la carga de mantenimiento de registrar esto en cada una de las 15 pruebas.

Sin embargo, ahora estoy escribiendo una prueba Test_MediaPlayerProxyFactoryThrowsException, lo que confirma que mi sistema maneja elegantemente un error del componente IMediaPlayerProxyFactory. En el método de ensayo que he creado mi aplicación simulada especial, y ahora quiero inyectarlo en el marco:

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

Pero Windsor lanza una Castle.MicroKernel.ComponentRegistrationException, con el mensaje "Ya existe un componente con ese nombre. "

¿Hay alguna manera de que pueda hacer que mi mockMediaPlayerProxyFactory sea la instancia predeterminada para el IMediaPlayerProxyFactory, descartando el componente que ya está registrado?


De acuerdo con la documentation, el castillo de Windsor 3 permite a las anulaciones de registro, pero sólo pude encontrar un ejemplo:

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

ConfigureFor es un método de la clase BasedOnDescriptor. En mi caso, no estoy usando FromDescriptor o BasedOnDescriptor.

Respuesta

55

Hay dos cosas que hay que hacer para crear una instancia primordial:

  1. asignarle un nombre único
  2. Llame al método IsDefault

Así que para que funcione el ejemplo :

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

Porque planeo usar este patten primordial en muchas pruebas, he creado mi propio método de extensión:

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

Ahora el ejemplo se puede simplificar a:

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


Posteriormente Editar

Versión 3.1 introduce el IsFallback método. Si registro todos mis componentes iniciales con IsFallback, los nuevos registros anularán automáticamente estos registros iniciales. Hubiera ido por ese camino si la funcionalidad estuviera disponible en ese momento.

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

+0

nombrar e invocar el método '.IsDefault' no son necesarios en la implementación real, aparte de eso, ¡muy bien! – bevacqua

+1

Gracias por actualizar la respuesta. –

1

No reutilice su contenedor durante las pruebas. En su lugar, configúrelo en null en el TearDown() y reinícielo para cada prueba real.

+0

Lo sentimos, no debo haber sido claro. Dispongo del contenedor en 'TearDown()', y lo reinicio en 'SetUp()'. Cambiaré mi introducción para tratar de hacerlo más explícito. –

Cuestiones relacionadas