TDD: scrivere un test separato per l'inizializzazione dell'oggetto o fare affidamento su altri test che lo eseguono

5

Questo sembra essere il modello comune che sta emergendo in alcuni dei test su cui ho lavorato ultimamente. Abbiamo una classe, e molto spesso questo è un codice legacy il cui design non può essere facilmente modificato, che ha un sacco di variabili membro.

C'è una sorta di funzione "Inizializza" o "Carica" che metterebbe un oggetto in uno stato valido. Solo dopo che è stato inizializzato / caricato, i membri sono nello stato appropriato in modo che altri metodi possano essere esercitati.

Quindi, quando iniziamo a scrivere test, il primo test è "TestLoad" e tutto ciò che inseriamo è l'esercizio della logica di inizializzazione. Quindi potremmo aggiungere uno (o alcuni) test TestLoadFailureXXX e quelli sono sicuramente preziosi.

Quindi iniziamo a scrivere test per verificare altri comportamenti, ma tutti richiedono che l'oggetto sia caricato. Quindi iniziano tutti con lo stesso codice di "TestLoad".

Quindi la mia domanda: TestLoad è addirittura necessario? Lo estrai e lasci che altri test semplicemente esercitino il caricamento? O lasciarlo così le cose sono più esplicite?

So che ogni funzione di test di unità non dovrebbe avere (o il meno possibile) una sovrapposizione con altre funzioni di test, ma sembra che nei casi di caricamento ciò sia inevitabile. E che ci piaccia o no, se qualcosa nel codice di caricamento si rompe, ci ritroveremo con un'intera suite di test di errori.

C'è un altro approccio che potrei mancare qui?

Grazie per le risposte. Ha sicuramente senso che tu voglia vedere "InitializationTest" e se fallisce sai dove iniziare a cercare.

Se è importante, questa domanda riguarda principalmente il C ++ e usiamo il framework CppUnit. E ora, grazie a sleske, continuerò a desiderare che CppUnit abbia supportato le dipendenze dei test. Potrebbe dover hackerare qualcosa in uno di questi giorni:)

    
posta DXM 08.06.2012 - 21:26
fonte

5 risposte

7

Se l'inizializzazione fallisce, ti piacerebbe che comparisse in un test chiaramente etichettato come test dell'inizializzazione, invece che in un test che nominalmente riguarda qualcos'altro.

E se il comportamento dipendente dall'inizializzazione fallisce, quando un test lo rileva, ti piacerebbe essere sicuro che l'errore sia nel comportamento testato nominalmente, e non l'inizializzazione, che è stata trattata in un test separato.

Quindi avere un test di inizializzazione separato aiuta a distinguere tra diverse condizioni di errore.

    
risposta data 08.06.2012 - 21:47
fonte
6

Come hanno già indicato le altre risposte, è utile disporre di un test separato solo per l'inizializzazione, perché se questo test fallisce, si sa che altri test falliti sono probabilmente dovuti all'inizializzazione, quindi ha senso affrontare prima questo .

Per i punti bonus, potresti voler utilizzare un framework di test con dipendenze di test (come TestNG ). Quindi è possibile contrassegnare tutti gli altri test per la classe in base al test di inizializzazione. Quindi, se il test di inizializzazione fallisce, gli altri test verranno saltati (con una nota appropriata). In questo modo puoi vedere immediatamente dove devi iniziare a cercare il problema.

    
risposta data 08.06.2012 - 21:55
fonte
2

Mi piace l'idea di "test come documentazione". Quindi, quando si inizializza una classe, dovrebbe essere in uno stato specifico, direi che dovrebbe esserci un test che verifica che sia effettivamente in quello stato specifico dopo l'inizializzazione, o che esegua alcune operazioni specifiche durante l'inizializzazione. Semplicemente perché funziona come documentazione per il comportamento previsto della logica di inizializzazione.

Is TestLoad even necessary?

Beh, probabilmente non "necessario" in quanto tale. Ma penso che sia una buona idea. Ricorda, il test è anche un indicatore della parte del codice che fallisce quando si introduce un bug. Avere un test unitario esplicito per il codice di inizializzazione può aiutare a identificare più rapidamente che è la logica di inizializzazione che è in errore.

Ma quando dici che tutti i test eseguono lo stesso codice di TestLoad, sembra che potresti esercitare un po 'più di riutilizzo del codice nel codice di test, condividere il codice di inizializzazione tra i test.

    
risposta data 08.06.2012 - 21:49
fonte
0

In un test in stile AAA (organizzare, agire, affermare, ad esempio xUnit), non vedo il punto. Capisco l'argomento che ti dà un test specifico che fallisce, ma che in realtà non aggiunge nulla. Il fatto che 10 test cadano tutti nell'inizializzazione degli oggetti dovrebbe essere davvero un indizio.

Ma, detto questo, questo è uno dei molti motivi per cui preferisco lo stile di test del contesto / specifica (ad esempio rSpec in Ruby - alcuni programmatori di Rails sembrano utilizzare il framework di default). Rimuove solo la domanda. Si inizializza una volta nel contesto e se il contesto non riesce, le specifiche non vengono mai eseguite.

    
risposta data 08.06.2012 - 22:41
fonte
0

Quello che mi manca nelle altre risposte è il seguente: quando dovresti testare il metodo di inizializzazione?

Un aspetto importante qui è: quanto è complesso il metodo di inizializzazione? Assegna semplicemente gli argomenti agli attributi? In questo modo:

void initialize(Foo fooThingy, Bar barObject) {
    this.foo = fooThingy;
    this.bar = barObject;
    this.baz = "Initialized with a constant";
}

Se è così, non mi preoccuperei di testarlo separatamente.

Tuttavia, se la logica è abbastanza complessa, ha un paio di edge case, ecc., quindi scriverò sicuramente più test per questo. Sia per il successo che per i casi di fallimento.

Per tutti gli altri test, assicurati di iniziare con un'istanza valida del SUT (Subject Under Test), preferibilmente costruita in un metodo di supporto. Ma poiché il metodo initialize non è banale, richiede più test.

    
risposta data 04.01.2016 - 09:23
fonte

Leggi altre domande sui tag