Classi di unit test con funzionalità online


23

Quando l'unità verifica le funzioni di una classe che ha funzioni private che richiedono funzionalità online. Come si farebbe per testarlo?

Per esempio:

public class Foo
{
    public int methodA()
    {
         int val = goOnlineToGetVal();

         return val;
    }

    private int goOnlineToGetVal()
    {
        CloudService c = new CloudService();
        int oval = c.getValueFromService();
        return oval;
    }
}

Se dovessi testare la funzione: 'methodA ()' tenterebbe di usare 'goOnlineToGetVal ()' che a sua volta proverebbe ad andare online, se questo test fosse fatto senza funzionalità. Come potrei accedere al 100% della copertura di classe senza andare online?


Il tuo metodo chiama semplicemente l'api cloud o fa anche un lavoro aggiuntivo?
Winston Ewert,


4
Iniezione di dipendenza ?
PhaDaPhunk,

Risposte:


76

new CloudService()

E c'è il tuo problema.

Il moderno design OO raccomanda che questo tipo di dipendenza sia trasmesso piuttosto che costruito direttamente. Questo può essere passato alla funzione stessa o alla classe in fase di costruzione. Potrebbe anche essere afferrato o aggregato da un contenitore Inversion of Control se questo tipo di complessità è giustificata.

A quel punto, diventa abbastanza banale passare in un servizio simulato / falso per fornirti i tuoi dati "online" durante i test. Meglio ancora, consente al tuo software di essere sufficientemente flessibile, in modo che tu possa adattarti rapidamente se arriva un client (governativo?) E non vuole usare il cloud per i suoi valori. Oppure vuoi scaricare un provider cloud per un altro. O...


7
Penso di essermi avvicinato molto di più alla comprensione di cosa diavolo l'iniezione di dipendenza.
marczellm,

Qual è il posto migliore per creare tutte le istanze necessarie alla mia applicazione? Il più vicino possibile alla parte superiore della mia domanda? Finora puoi applicare solo l'iniezione di dipendenza; a un certo punto dovrai creare tu stesso le istanze invece di farle passare come argomenti.
Paolo,

3
@Paul - Dipende. Nella mia esperienza, le applicazioni molto spesso sembrano alberi binari: una classe / funzione / modulo ne incolla due insieme per fornire un comportamento più complesso. Una di quelle classi di "colla" è quella che specifica l'implementazione concreta, che a sua volta viene utilizzata da qualcosa sopra che la incolla con qualcos'altro, che a sua volta ... fino a quando non si arriva al punto di entrata che incolla i pezzi grandi insieme coerentemente. Il posto "migliore" è il luogo che consente al codice di fare ciò che deve fare, senza farlo o conoscere cose che non dovrebbe. Varierà.
Telastyn,

2
@Paul Di solito la tua applicazione è divisa in una "libreria", che è testata direttamente e dovrebbe usare questo tipo di iniezione di dipendenza e codice specifico dell'applicazione. Quest'ultimo di solito si riduce a qualche GUI, qualche servizio web o qualche interfaccia a riga di comando che chiama direttamente la libreria con i dati forniti dall'utente. In sostanza, il codice specifico dell'applicazione creerà le implementazioni concrete che si aspetta la libreria a iniezione di dipendenza.
Darkhogg,

@Paul Dai un'occhiata ai container IoC come Castle Windsor, StructureMap, Ninject e Unity. Non sono affatto l'unico modo per fare l'iniezione di dipendenza, ma possono essere molto istruttivi in ​​termini di pensiero sulla costruzione di un grafico a oggetti, dall'alto verso il basso
Ben Aaronson,

37

Lo implementerei così:

public class Foo
{
    private ICloudService cloudService;

    public Foo(ICloudService s)
    {
       cloudService=s;
    }

    public int methodA()
    {
         int val = goOnlineToGetVal();

         return val;
    }

    private int goOnlineToGetVal()
    {
        int oval = cloudService.getValueFromService();
        return oval;
    }
}

L'interfaccia ICloudServicepuò essere implementata con una simulazione per il test o con il "vero" servizio cloud. Quando l'istanza new CloudService()è obbligatoria per ogni chiamata getValueFromServiceo CloudServiceproviene da un'API di terze parti che non può essere modificata, implementare un wrapper, derivante da ICloudServiceed effettuare le chiamate appropriate.


1
Questa è sicuramente la strada da percorrere. Ci sono librerie di classi che possono deridere un'interfaccia dandoti il ​​controllo assoluto del test.
Greg Burghardt,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.