2012-02-12 9 views
21

Sto tentando di utilizzare il castello di Windsor nel mio test automatizzati in questo modo:Nel Castello di Windsor 3, sovrascrivere una registrazione componente esistente in una prova di unità

Su ogni prova:

  • La funzione Setup() crea un contenitore Windsor, registrando implementazione di default di ogni componente
  • la Test funzione di accesso componente tramite il metodo IWindsorContainer.Resolve<T>, e verifica il loro comportamento
  • il TearDown() dispone di funzione del contenitore Windsor (ed eventuali componenti creati)

Ad esempio, potrebbero avere 15 test che accede componenti che indirettamente risultati nella creazione di un componente IMediaPlayerProxyFactory. La funzione SetUp registra un'implementazione sufficientemente buona IMediaPlayerProxyFactory, pertanto non ho l'onere di eseguire la registrazione in ciascuno dei 15 test.

Tuttavia, ora sto scrivendo un test Test_MediaPlayerProxyFactoryThrowsException, confermando che il mio sistema gestisce elegantemente un errore dal componente IMediaPlayerProxyFactory. Nel metodo di prova ho creato la mia speciale implementazione mock, e ora voglio iniettarla nel quadro:

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

Ma Windsor lancia un Castle.MicroKernel.ComponentRegistrationException, con il messaggio "C'è già un componente con quel nome. "

Esiste un modo per rendere il mio mockMediaPlayerProxyFactory l'istanza predefinita per lo IMediaPlayerProxyFactory, scartando il componente già registrato?


Secondo il documentation, Castello di Windsor 3 consente per le sostituzioni di registrazione, ma sono riuscito a trovare solo un esempio:

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

ConfigureFor è un metodo della classe BasedOnDescriptor. Nel mio caso non sto usando il FromDescriptor o BasedOnDescriptor.

risposta

55

Ci sono due cose che si devono fare per creare un'istanza prioritario:

  1. Assegnare un nome univoco
  2. chiamata al metodo IsDefault

in modo da ottenere l'esempio funzioni :

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

Perché ho intenzione di utilizzare questo patten overriding in molti test, ho creato il mio metodo di estensione:

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

Ora l'esempio può essere semplificata per:

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


tardi Modifica

La versione 3.1 introduce la IsFallback metodo. Se registro tutti i miei componenti iniziali con IsFallback, qualsiasi nuova registrazione sostituirà automaticamente queste registrazioni iniziali. Avrei percorso questa strada se la funzionalità fosse disponibile al momento.

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

+0

nome e invocazione del metodo '.IsDefault' non sono necessari per l'implementazione reale, a parte questo, molto bello! – bevacqua

+1

Grazie per aver aggiornato la risposta. –

1

Non riutilizzare il contenitore per i test. Invece, impostalo su null nello TearDown() e inizializzalo nuovamente per ogni test effettivo.

+0

Mi dispiace, non deve essere stato chiaro. Dispongo del contenitore in 'TearDown()', e lo reinizializzo in 'SetUp()'. Cambierò la mia introduzione per cercare di renderla più esplicita. –

Problemi correlati