Sembra che il consenso generale per le classi di test unitari sia quello di testare il tuo oggetto solo attraverso la sua interfaccia pubblica. Quindi, se volevi testare il metodo removeElement
su una classe LinkedList dovresti chiamare addElement
, poi removeElement
e infine containsElement
per affermare che l'elemento è stato rimosso.
Questo è fragile perché se addElement
o containsElement
si rompono, il test fallirà anche se l'implementazione di removeElement
è corretta.
Quando provo le procedure standalone, provo a chiamarle isolatamente. Se dovessi testare una procedura removeElement
, creerò lo stato dei parametri direttamente nel test e poi asserirò che lo stato della chiamata è corretto.
L'unica differenza tra un metodo e una procedura è che a un metodo viene assegnato implicitamente l'oggetto come parametro. Quindi dal momento che list.removeElement(el)
e removeElement(list, el)
sono funzionalmente uguali, perché non testarli allo stesso modo? per esempio. Nel test, crea un'istanza della classe LinkedList, configura i suoi campi "privati", chiama removeElement
, e asserisci i suoi campi post-call modificati correttamente.
Questo è il test unitario ideale perché riguarda l'input e l'output di asserzione per una singola unità di funzionalità. Dover chiamare metodi pubblici A, B, C, D, E e F solo per testare il metodo G è un test di integrazione borderline, può potenzialmente creare falsi positivi (poiché i dati stessi non vengono mai convalidati), e rende isolante il fallimento del test durante la manutenzione più difficile.
Ho scoperto in modo anonimo che il test della scatola nera tenta gli sviluppatori di aggiungere metodi pubblici non necessari per rendere il loro test "più semplice" ma aumenta la manutenzione a lungo termine.
Quindi la mia domanda è: perché il test della scatola bianca è scoraggiato nel mondo OO quando sembra che abbia un senso comune nel mondo procedurale e funzionale?
EDIT : esiste un modo OO per gestire i grip che ho delineato nel mio post, in particolare nella parte successiva che not implica l'aggiunta di nuovi metodi pubblici ed evitare di chiamare metodi pubblici diversi da quelli testati? Considera il dilemma di affermare il puntatore del nodo "precedente" nel mio commento .
EDIT # 2 : Apparentemente il mio concetto di classe potrebbe essere diverso dagli altri. Una classe per me è solo un (molto vecchio) modello di progettazione: "costrutto", "consuma" (ad es. Metodi di chiamata) e "destruct" che non è diverso da fopen
, fread, fwrite fseek
e fclose
in C Indipendentemente dal fatto che sia implicato un parametro implicito, le cose vengono riempite dietro uno spazio dei nomi, o vengono chiamate private, pubbliche o protette, tutto è solo trasformazioni di dati e dati alla fine della giornata. Ho difficoltà a cogliere le classi come un'unità quando sembra più simile a un modello di progettazione o addirittura a un "contenitore" per le unità reali che sono le funzioni stesse.