Astenersi dall'utilizzare il contenitore DI nei test dell'unità. Nei test di unità, si tenta di testare una classe o un modulo in isolamento e c'è poco uso per un contenitore DI in quella zona.
Le cose sono diverse con i test di integrazione, dal momento che si desidera verificare come i componenti del sistema si integrano e lavorano insieme. In tal caso, si utilizza spesso la configurazione DI di produzione e si scambiano alcuni dei servizi per servizi falsi (come ad esempio il MailService
) ma si avvicina il più possibile alla cosa reale.In questo caso si utilizza il contenitore per risolvere l'intero grafico dell'oggetto.
Anche il desiderio di utilizzare un contenitore DI nei test dell'unità deriva spesso da modelli inefficaci. Ad esempio, se si tenta di creare la classe sotto test con tutte le sue dipendenze in ciascun test, si ottiene un sacco di codice di inizializzazione duplicato e un piccolo cambiamento nella classe sottoposta a test può in tal caso propagarsi attraverso il sistema e richiedere di cambia dozzine di test unitari. Questo ovviamente causa problemi di manutenibilità.
Uno schema che mi ha aiutato molto in passato è l'uso di un semplice metodo di prova specifico per classe. Questo metodo centralizza la creazione della classe sottoposta a test e riduce al minimo la quantità di modifiche da apportare quando le dipendenze della classe in prova cambiano. Questo è il modo come metodo factory potrebbe apparire come:
private ClassUnderTest CreateValidClassUnderTest(params object[] dependencies) {
return new ClassUnderTest(
dependencies.OfType<ILogger>().SingleOrDefault() ?? new FakeLogger(),
dependencies.OfType<IMailSender>().SingleOrDefault() ?? new FakeMailer(),
dependencies.OfType<IEventPublisher>().SingleOrDefault() ?? new FakePublisher());
}
Questo metodo factory contiene una matrice params
che accetta qualsiasi dipendenza. Il codice estrae le dipendenze dall'elenco e nel caso in cui manchi una particolare dipendenza, verrà iniettata una nuova implementazione falsa.
Questo funziona, poiché nella maggior parte dei test si è interessati solo a una o due dipendenze. Le altre dipendenze sono necessarie per il funzionamento della classe, ma non sono interessanti per il test specifico. Il metodo factory consente quindi di fornire solo le dipendenze che sono interessanti per il test in corso, rimuovendo il rumore delle dipendenze non utilizzate. Il metodo factory permette quindi di scrivere il seguente test:
public void Test() {
// Arrange
var logger = new ListLogger();
var cut = CreateValidClassUnderTest(logger);
// Act
cut.DoSomething();
// Arrange
Assert.IsTrue(logger.Count > 0);
}
Se siete interessati ad imparare a scrivere leggibili test affidabile e mantenibile, vi consiglio di leggere il libro di Roy Osherove The Art of Unit Testing (seconda edizione). Questo mi ha aiutato moltissimo.
Non so quale modello cerchi. Perché non creare solo i contenitori nell'inizializzazione di test (costruttore di xunit, ad es.)? Lo schema è semplice: composizione. – Artyom
Se sei veramente interessato ai modelli di test unitario, dovresti leggere [xUnit Test Patterns] (https://www.amazon.co.uk/xUnit-Test-Patterns-Refactoring-Code-ebook/dp/B004X1D36K/ref = dp_kinw_strp_1). – Steven