Come test unitario viene utilizzata la corretta implementazione di un'interfaccia?

5

Ho questo problema con i test delle unità per anni. Il test delle unità dovrebbe testare le unità isolate, cioè, se usiamo il vocabolario di interfaccia / implementazione, dovrebbe testare le classi di implementazione concreta. Bene, facciamolo. In un codice che è il client dell'interfaccia, si dovrebbe prendere in giro l'interfaccia per soddisfare i test. Va bene, facciamolo dove possibile, anche.

Ma poi, nel codice di produzione, c'è un posto in cui la classe di implementazione effettiva viene istanziata e utilizzata come l'istanza che implementa l'interfaccia. Può essere un metodo di fabbrica, può essere da qualche altra parte.

Ho il problema di testare realmente questa colla tra questi due, testati isolatamente, strati. L'uso di varianti di instance of è fragile, per non dire che il creatore dell'istanza reale può essere "intelligente" e scegliere un'implementazione diversa in base alle circostanze. Anche se non lo è, crea quell'istanza usando alcune configurazioni in giro.

Finora, non eseguo test unitari in modo rigoroso (quindi non faccio new Foo(directa, directb) , ma createApp(indirectA, indirectB).getFoo() ), ma potrebbe non essere il test dell'unità corretto. Ciò non verifica tutte le implementazioni, che testano quelle implementazioni-app-usi. Un altro approccio che potrei vedere è quello di effettuare test del parametro di implementazione di Foo, con un metodo factory makeFoo(a,b) e creare sottoclassi per ogni implementazione e uno che crea tali istanze tramite un'app reale.

Conosci un buon modo su come affrontarlo?

In altre parole, la domanda potrebbe essere semplicemente "Come testare (unità) il codice della colla?"

    
posta herby 25.02.2015 - 17:40
fonte

4 risposte

3

In seguito al link parla di @jbrains, pubblicato da @ThomasRuiz, sono arrivato a questa conclusione:

  • Scrivi i test del contratto (il discorso ne ha una definizione rigorosa, ne ho uno sfuggito: "test che usano solo API pubbliche della classe").
  • Smetti di usare new FooImpl(fooConfig) per creare implementazioni di "istanza che soddisfa Foo di contratto", invece, rendi obbligatorio per il tuo codice avere createFoo(fooConfig) metodo factory per creare un'istanza del Foo di lavoratore a contratto (forse dovrebbe essere chiamato hireFoo ;-)).
  • I test del contratto devono essere testati contro client.createFoo(testFooConfig) . Potresti finire con la necessità che il cliente sia higherClient.createBar(...) stesso. Questo è lo spot della settimana dell'intera faccenda. Forse dovrei chiedere.jbrains.ca ...: - \

EDIT: parlato con @jbrains. Il risultato è:

  • I tuoi costruttori non dovrebbero creare i collaboratori. Idealmente, li fanno iniettare, come new Foo(collab1, collab2);
  • Applicando questo all'estremo, finisce con la creazione di tutti i (!!!) collaboratori in primo piano nel livello più in alto. Vedi link . Guardalo come una configurazione dell'app.
  • Citazione " new A(new B(new E()), new C(new F(), new G()), new D()) va bene. A crea B , che crea E (e così via) causa problemi", in link .

Finalmente so quale sia l'effettiva dipendenza da iniezione e perché è importante (il tuo codice diventa effettivamente testabile e disaccoppiato, tutto il codice della colla è in un posto ed è l'unico pezzo non testato).

    
risposta data 26.02.2015 - 12:29
fonte
7

Il modo in cui testate il codice della colla è eseguendo un test di integrazione .

The purpose of integration testing is to verify functional, performance, and reliability requirements placed on major design items. These "design items", i.e. assemblages (or groups of units), are exercised through their interfaces using black box testing, success and error cases being simulated via appropriate parameter and data inputs.

Simulated usage of shared data areas and inter-process communication is tested and individual subsystems are exercised through their input interface. Test cases are constructed to test whether all the components within assemblages interact correctly, for example across procedure calls or process activations, and this is done after testing individual modules, i.e. unit testing.

    
risposta data 25.02.2015 - 21:50
fonte
6

Esistono due modi per scrivere i test delle unità. La maggior parte delle persone pensa che ci sia solo un modo. Se si utilizzano test socievoli, è possibile testare la colla come parte del test.

    
risposta data 25.02.2015 - 22:06
fonte
2

But then, in the productions code, there is some place where the actual implementation class is instantiated and used as the-instance-that-implements the interface. It may be factory methods, it can be somewhere else.

How do you test that?

Qui ci sono tre scenari.

Il primo è che non ti interessa l'istanza utilizzata. Alcuni codici usano internamente qualche istanza concreta per fare il suo lavoro e quel codice è già di dimensioni "unitarie". È fantastico. Ignora i dettagli di implementazione e verifica gli input / output.

Il secondo è una sorta di fabbrica. Per alcuni dati input, ottieni l'output corretto. È un'unità facile da testare come qualsiasi altra unità: fornire alcuni input (tendenti a condizioni al contorno) e assicurarsi che l'uscita sia corretta. Solitamente instanceof è sufficiente, ma puoi controllare il comportamento dell'oggetto risultante se è semplice / ovvio / invariato.

Il terzo è il tipo di codice di configurazione. Potrebbe essere la configurazione stessa, oppure potrebbe essere un input hardcoded a un codice più generale. Per esempio, in quasi tutte le mie app, tutto main fa è specificare istanze concrete e incollarle insieme. Non collaudo l'unità di quel codice, e non ti consiglio nemmeno di farlo.

Perché? Perché non offre alcun vantaggio. Esiste un test unitario per fornire precoci e chiari segni che qualcosa non va. Nella mia esperienza, se hai rovinato la tua istanza concreta (e hai un'architettura relativamente sana), la semplice esecuzione dell'app fornisce un indicatore rapido, chiaro ed economico se le cose sono configurate correttamente o meno.

    
risposta data 25.02.2015 - 22:20
fonte

Leggi altre domande sui tag