Domanda

Sto provando a imparare l'iniezione delle dipendenze e ho riscontrato un problema, quando l'unità ha testato l'applicazione.

Sto scrivendo un'applicazione console e il contenitore viene creato e inizializzato in Main (), è disponibile come get-property in Program.Container, quindi ovunque nella mia applicazione posso chiamare Program.Container.Resolve<..>().

Ho una classe ServiceValidator come questa:

public class ServiceValidator
{
    private readonly IConfiguration _configuration;
    private readonly IService _service;

    public ServiceValidator(IConfiguration configuration, IService service)
    {
        _configuration = configuration;
        _service = service;
    }

In un'altra classe che uso

ServiceValidator serviceValidator = Program.Container.Resolve<ServiceValidator>();
serviceValidator.VerifyVersion();

È la chiamata a Program.Container.Resolve che mi causa problemi nel test unitario, poiché non è stato impostato.

È una cattiva pratica chiamare la risoluzione sul contenitore? Potrei creare l'istanza di ServiceValidator in Main() e passare l'oggetto in giro, ma questo sembra stupido in quanto causerebbe molti parametri per gli oggetti che sono stati passati al metodo successivo.

Quindi immagino sia accettabile chiamare Resolve all'interno di una classe, ma il contenitore deve essere configurato per il test unitario. Come dovrei farlo, dovrei spostare il container in un posto diverso dalla classe Program? Cosa consiglieresti?

Se è importante, sto usando Unity e C #

Grazie :-)

È stato utile?

Soluzione

  

È una cattiva pratica chiamare la risoluzione sul contenitore? Potrei creare l'istanza ServiceValidator in Main () e passare l'oggetto in giro, ma questo sembra stupido in quanto causerebbe molti parametri per gli oggetti che sono stati passati al metodo successivo.

Quando si utilizza completamente l'iniezione di dipendenza, non sarà necessario passare molti parametri agli oggetti. Il costruttore di ogni oggetto dovrebbe avere come parametri solo le dipendenze che esso stesso utilizza direttamente - non saprà delle dipendenze transitive delle sue dipendenze dirette.

Quindi se hai una classe X che richiede un ServiceValidator, allora la classe X avrà un parametro di costruzione di tipo ServiceValidator. Quindi se una classe Y utilizza la classe X, allora la classe Y avrà un parametro di costruzione di tipo X. Nota che Y non sa nulla su ServiceValidator, quindi non è necessario passare ServiceValidator da una classe a un altro - l'unico posto dove viene usato è quando si costruisce X, e ciò è spesso fatto da un framework DI o in un solo posto in una fabbrica scritta a mano.

Alcuni collegamenti per ulteriori informazioni:

Altri suggerimenti

Di solito consento alle chiamate di risolvere le dipendenze dal contenitore in luoghi come principale, anche se cerco ancora di ridurle al minimo. Quello che faccio allora è configurare il contenitore in un metodo di inizializzazione di una classe di test. L'ho inizializzato con implementazioni false per qualsiasi classe di test che deve chiamare il contenitore.

Le classi di test che non chiamano nulla che richiede l'inizializzazione del contenitore sono quindi in grado di ignorarlo e non usare i falsi. Di solito uso derisioni in quei casi.

Uso anche Microsoft Service Locator in modo che la dipendenza che sto prendendo è su qualcosa da .NET Framework anziché su un contenitore specifico. Questo mi permette di usare tutto ciò che desidero anche in un contenitore preparato in casa.

È possibile utilizzare una classe statica come inizializzatore per il proprio contenitore. Qualcosa come BootStrapper.cs andrebbe bene. È quindi possibile fare riferimento ai metodi di classe sia nel codice che nei test.

Bene, ciò che tecnicamente stai facendo è un luogo di servizio nella tua classe.

Ricordo di aver letto questo articolo qualche tempo fa:

http://martinfowler.com/articles/injection.html

Per le mie lezioni non provo mai ad usare Resolve in esse. Creo gli oggetti attraverso il contenitore quando ne ho bisogno. Per i test unitari, utilizzo alcune librerie simulate e classi stub.

Il problema sta nel fatto che stai provando a testare il metodo Main. Questo metodo è praticamente impossibile da testare l'unità.

Direi che è meglio non testare l'unità sul metodo principale perché:

  • L'enfasi dei moderni test unitari riguarda il design
  • È necessario ridurre al minimo la dipendenza dalla configurazione nei test unitari. La configurazione può essere testata con test del fumo o di integrazione.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top