2012-05-12 6 views
6

ho familiarità con i principi fondamentali del TDD, essendo:Qual è l'approccio migliore per il test delle unità quando si hanno interfacce con implementazioni sia fittizie che reali?

  1. test di scrittura, queste verranno a mancare a causa di alcuna implementazione
  2. Scrivi implementazione di base per effettuare test passano
  3. codice Refactor

Tuttavia, sono un po 'confuso su dove si integrano interfacce e implementazione. Sto creando un'applicazione web Spring nel mio tempo libero, e piuttosto che andare in armi da fuoco, mi piacerebbe capire come posso testare le interfacce/implementazioni un po 'meglio, prendere questo semplice codice di esempio che ho creato qui:

public class RunMe 
{ 

    public static void main(String[] args) 
    { 
     // Using a dummy service now, but would have a real implementation later (fetch from DB etc.) 
     UserService userService = new DummyUserService(); 
     System.out.println(userService.getUserById(1)); 
    } 
} 

interface UserService 
{ 
    public String getUserById(Integer id); 
} 

class DummyUserService implements UserService 
{ 
    @Override 
    public String getUserById(Integer id) 
    { 
     return "James"; 
    } 
} 

ho creato l'interfaccia UserService, in ultima analisi, ci sarà una vera e propria attuazione del presente che interrogare un database, ma al fine di ottenere l'applicazione decollare ho sostituito un'implementazione DummyUserService che sarà solo ritorno alcuni dati statici per ora.

Domanda: Come posso implementare una strategia di test per quanto sopra?

ho potuto creare una classe di test chiamato DummyUserServiceTest e la prova che quando chiamo getUserById() che tornerà James, sembra abbastanza semplice, se non una perdita di tempo (?).

Successivamente, è stato anche possibile creare una classe di prova RealUserService per verificare che getUserById() restituisca un nome utente dal database. Questa è la parte che mi confonde leggermente, nel fare ciò, questo non supera in modo sostanziale il limite di un test unitario e diventa più un test di intergrazione (con il colpo sul DB)?

Domanda (migliorata, un po '): quando si utilizzano interfacce con fittizio/stubato e implementazioni reali, quali parti devono essere testate dall'unità e quali parti possono essere tranquillamente lasciate non testate?

ho trascorso un paio d'ore Googling su questo argomento la scorsa notte, e per lo più trovato sia esercitazioni su ciò che TDD è, o esempi di come utilizzare JUnit, ma niente nei regni di consulenza ciò che dovrebbe in realtà essere testato. È del tutto possibile però, che non ho cercato abbastanza o non stavo cercando la cosa giusta ...

risposta

4

Non testare le implementazioni fittizie: non saranno utilizzate in produzione. Non ha alcun senso testarli.

Se la reale implementazione di UserService non fa altro che accedere a un database e ottenere il nome utente tramite il suo ID, il test dovrebbe verificare che lo faccia e lo faccia correttamente. Chiamalo un test di integrazione, se vuoi, ma è comunque un test che dovrebbe essere scritto e automatizzato.

La strategia abituale consiste nel compilare il database con i dati di test minimi nel metodo @Before annotato del test e verificare che il metodo di test verifichi che per un ID presente nel database, venga restituito il nome utente corrispondente.

0

La risposta di JB è buona, ho pensato di buttare fuori un'altra tecnica che ho usato.

Quando si sviluppa il test originale, non preoccuparsi di estinguere lo UserService in primo luogo. In effetti, vai avanti e scrivi la cosa reale. Procedere nel modo seguente: Kent Beck's 3 rules.

1) Farlo funzionare. 2) Fai bene. 3) Fallo veloce.

Il codice eseguirà test che verificheranno la ricerca tramite id. Come dichiarato da JB, i test saranno considerati test di integrazione a questo punto. Una volta che sono passati abbiamo raggiunto con successo il passaggio 1. Ora, guarda il design. È giusto? Modifica gli odori del design e controlla il passaggio 2 dall'elenco.

Per il passaggio 3, è necessario eseguire questo test rapidamente. Sappiamo tutti che i test di integrazione sono lenti e soggetti a errori con tutte le impostazioni di gestione delle transazioni e database. Una volta che sappiamo che il codice funziona, in genere non mi preoccupo dei test di integrazione. È in questo momento che è possibile introdurre il proprio servizio fittizio, trasformando efficacemente il test di integrazione in un test unitario. Ora che non tocca il database in alcun modo, possiamo controllare il passaggio 3 dall'elenco perché questo test è ora veloce.

Quindi, quali sono i problemi con questo approccio? Bene, molti diranno che ho ancora bisogno di un test per il database supportato UserService. Di solito non mantengo i test di integrazione nel mio progetto. La mia opinione è che questi tipi di test sono lenti, fragili e non riescono a rilevare errori logici sufficienti nella maggior parte dei progetti da ripagare da soli.

Spero che questo aiuti!

Brandon

3

ti consiglierei di leggere questo libro prima: Growing Object-Oriented Software Guided by Tests da Steve Freemand e Nat Pryce. Risponde alla tua domanda e a molte altre, relative a TDD.

Nel tuo caso particolare, devi configurare il tuo RealUserService con un adattatore DB, che renderà le query DB reali. Il servizio stesso sarà il servizio, non la persistenza dei dati. Leggi il libro, sarà di grande aiuto :)

Problemi correlati