Come testare l'unità senza derisioni e non essere legato a implementazioni concrete di un'interfaccia

2

Mi considero un 'mockist' sul dibattito 'mockista' contro 'classicista', ma sto cercando di capire l'altro punto di vista.

Immagina di avere questa classe, in cui un'istanza concreta di IDependency viene iniettata da un contenitore IoC.

IDependency non accede a una risorsa remota come un database o un servizio web (nel qual caso definirò definitivamente il mocking), è solo un'altra classe contenente alcune logiche di business.

public class UnitUnderTest
{
    public UnitUnderTest ( IDependency dependency )
    {
    }
}

Usando questo modello, sono libero di cambiare l'implementazione concreta di IDependency cambiando la classe iniettata dal contenitore IoC. Non sono legato a nessuna particolare implementazione.

Se dovessi testare questa classe senza il mocking IDependency , non dovrei istanziare il reale IDependency da passare al costruttore?

public class My_Unit_Test()
{
    IDependency concreteDependency = new ConcreteDependency();
    var unitUnderTest = new UnitUnderTest(concreteDependency);
}

In questo esempio, se scrivo una sostituzione a ConcreteDependency , dovrei non solo cambiare la configurazione del mio contenitore IoC, ma tutti i miei test unitari che usano ConcreteDependency .

Oppure ... utilizzo lo stesso contenitore IoC all'interno dei miei test di unità (che sembra contrario all'idea di testare le cose in isolamento)?

    
posta Dave S 14.05.2014 - 18:01
fonte

2 risposte

7

If I was to test this class without mocking IDependency, wouldn't I have to instantiate my real IDependency to pass in to the constructor?

No, potresti creare un falso IDependency per le tue esigenze specifiche. Potresti persino rendere il tuo "reale" IDependency ma parametrizzarlo in modo specifico per le tue esigenze. Sebbene dipendano da chi si parla, questi sono considerati oggetti finti poiché non vengono utilizzati nella produzione.

Questo è l'argomento comune contro il deridere tutto: hai già degli oggetti per fare cose robuste, flessibili e affidabili. Non prendi in giro IList nei tuoi test perché List è una dipendenza, vero?

Come la maggior parte degli argomenti, l'approccio migliore è spesso un equilibrio tra i due.

In this example, if I write a replacement to ConcreteDependency, I would have to not only change my IoC container configuration, but all of my unit tests that use ConcreteDependency.

Sì, proprio come dovresti cambiare tutti i tuoi mock se dovessi sostituire i tuoi oggetti finti.

How to unit test without mocks and not be tied to a concrete implementations of an interface

Non puoi letteralmente.

Devi creare un'implementazione concreta di quell'interfaccia da qualche parte . È possibile condividere questa istanza tra i test, ma ciò è contrario alle migliori pratiche (i test non sono isolati). Potresti avere una factory per generare l'oggetto, ma poi hai aggiunto la complessità ed è raro che un singolo tipo di istanza possa essere usato per ogni test. Ma alla fine, il test ha bisogno di un'implementazione concreta per funzionare, indipendentemente da quanta indiretta hai messo tra il test e la cosa.

    
risposta data 14.05.2014 - 18:31
fonte
4

Hai solo bisogno di un contenitore IoC se vuoi centralizzare le dichiarazioni delle dipendenze. Per tutto il resto, c'è un'iniezione ordinaria del costruttore.

Per dirla in un altro modo, non hai bisogno di un contenitore IoC nei test delle tue unità. Non stai testando il contenitore IoC, dopotutto.

Per dirla in un altro modo, se stai cucendo insieme una serie di dipendenze fittizie nei tuoi test unitari usando un contenitore IoC, non sono più test unitari; sono test di integrazione (test di integrazione mock , se esiste una cosa del genere).

    
risposta data 14.05.2014 - 18:20
fonte

Leggi altre domande sui tag