2014-10-21 2 views
5

Attualmente sto utilizzando Simple Injector per la prima volta. Nel mio progetto .NET Sono in esecuzione di test e dati beffardo tornato da un servizio Web e registrare l'oggetto al contenitore in questo modoIniettore semplice, non può ignorare la registrazione esistente

_container.Register<IWebServiceOrder>(() => mock.Object, Lifestyle.Transient); 

Questo funziona bene. Ma nei miei test voglio testare il comportamento del sistema su una seconda chiamata al servizio web che conterrà dati aggiornati, quindi l'oggetto mock dovrà essere aggiornato.

Per impostazione predefinita, Simple Injector non consente l'override delle registrazioni esistenti ma il sito Web ufficiale afferma che è possibile modificare questo comportamento come di seguito.

https://simpleinjector.readthedocs.org/en/latest/howto.html#override-existing-registrations

container.Options.AllowOverridingRegistrations = true; 

Purtroppo ancora ottengo un errore quando si tenta di registrare l'oggetto una seconda volta anche con il codice di cui sopra.

Il contenitore non può essere modificato dopo la prima chiamata a getInstance, GetAllInstances e Verifica

Tutte le idee su perché questo sta accadendo?

+0

Vedere [qui] (https://simpleinjector.readthedocs.org/en/latest/decisions.html#the-container-is-locked-after-the-first-call-to-resolve) perché il contenitore è bloccato dopo la prima chiamata da risolvere. – qujck

risposta

9

Sostituire una registrazione esistente dopo aver già lavorato con il contenitore non ha quasi mai il comportamento che ci si aspetterebbe (e ciò vale per tutte le librerie DI) e questo è il motivo per cui il contenitore Simple Injector è bloccato. Questo è descritto in ulteriori dettagli here (come già sottolineato da @qujck).

Prima di tutto, se si stanno scrivendo i test di unità, non si deve usare affatto un contenitore. Il test di unità dovrebbe creare la classe in prova se stessi, oppure estrarre questa logica ad un metodo factory pratico, come ad esempio:

private static MailNotifier CreateMailNotifier(
    IDeposit deposit = null, ISendMail mailSender = null, ILog logger = null) 
{ 
    return new MailNotifier(
     deposit ?? Substitute.For<IDeposit>(), 
     mailSender ?? Substitute.For<ISendMail>(), 
     logger ?? Substitute.For<ILog>()); 
} 

Questo metodo di fabbrica è una variante al Test Data Builder pattern.

Facendo uso di parametri opzionali, permette il test di unità per specificare solo l'attuazione falso richiede durante i test:

public void Notify_WithValidUser_LogsAMessage() 
{ 
    // Arrange 
    var user = new User(); 

    var logger = new FakeLogger(); 

    MailNotifier sut = CreateMailNotifier(logger: logger); 

    // Act 
    sut.Notify(user); 

    // Assert 
    Assert.AreEqual(expected: 1, actual: logger.LoggedMessages.Count); 
} 

Se si utilizza un contenitore, in quanto la creazione della classe in prova a mano è troppo ingombrante, indica un problema nella tua classe sotto test (molto probabilmente una violazione del Principio di Responsabilità Unica). Impedire l'utilizzo di strumenti per aggirare i problemi nella progettazione; il tuo codice ti sta parlando.

Per i test di integrazione, tuttavia, è molto più usuale utilizzare il contenitore, ma in tal caso è sufficiente creare un nuovo contenitore per ogni test di integrazione. In questo modo è possibile aggiungere o sostituire il IWebServiceOrder senza alcun problema.

+0

Ottima risposta. Test unitari - no, non usare il contenitore DI, ma i test di integrazione - sì, totalmente d'accordo. Sto solo facendo un gioco a casa con EF6, Simple Injector e SpecFlow e questo funziona bene - ci sono alcune cose che voglio sostituire nei miei test di integrazione - principalmente lavorando con DateTime - Ho un servizio per ottenere l'attuale datetime.Al lavoro abbiamo un test unitario per le registrazioni Unity che agisce più come un test del fumo in quanto consente registrazioni non valide/incomplete utilizzando InjectionConstructor ma questo trova tutti i problemi in anticipo. NOTA: non ci sono verifiche con la versione di Unity che usiamo. – Andez

+0

@Andrez avrai trovato tutti i problemi in questo test del fumo con Unity. Dai un'occhiata a [diagnostica] (https://simpleinjector.org/diagnostics) che Simple Injector esegue durante la verifica e dimmi se riesci a rilevare questi tipi di errori in primo piano con Unity. – Steven