Qual è il valore del controllo nei test unitari falliti?


13

Mentre ci sono modi per impedire l'esecuzione dei test unitari, qual è il valore del controllo in unit test falliti?

Userò un semplice esempio: Case sensitive. Il codice corrente fa distinzione tra maiuscole e minuscole. Un input valido nel metodo è "Cat" e restituirebbe un enum di Animal.Cat. Tuttavia, la funzionalità desiderata del metodo non dovrebbe fare distinzione tra maiuscole e minuscole. Quindi, se il metodo descritto fosse passato "gatto", potrebbe restituire qualcosa come Animal.Null invece di Animal.Cat e il test unitario fallirebbe. Anche se una semplice modifica del codice farebbe funzionare tutto ciò, un problema più complesso potrebbe richiedere settimane per risolvere, ma identificare il bug con un test unitario potrebbe essere un'attività meno complessa.

L'applicazione attualmente analizzata ha 4 anni di codice che "funziona". Tuttavia, recenti discussioni riguardanti i test unitari hanno riscontrato difetti nel codice. Alcuni necessitano solo di una documentazione esplicita dell'implementazione (es. Maiuscole o minuscole) o di un codice che non esegue il bug in base al modo in cui viene attualmente chiamato. Tuttavia, è possibile creare unit test eseguendo scenari specifici che consentano di visualizzare il bug e che siano input validi.

Qual è il valore del controllo nei test unitari che esercitano il bug fino a quando qualcuno non riesce a risolvere il codice?

Questo test unitario dovrebbe essere contrassegnato con ignora, priorità, categoria ecc. Per determinare se un build ha avuto esito positivo in base ai test eseguiti? Alla fine il test unitario dovrebbe essere creato per eseguire il codice una volta che qualcuno lo corregge.

Da un lato mostra che i bug identificati non sono stati corretti. Dall'altro, potrebbero esserci centinaia di test unitari falliti che compaiono nei log e che eliminano quelli che dovrebbero fallire vs. fallimenti a causa di un check-in di codice sarebbe difficile da trovare.


Questo è un modo per aumentare i numeri di copertura del test.
JeffO

Se hai già tentato di scrivere il test unitario, perché dovresti riscriverlo quando decidi di risolvere il problema? Solo perché è registrato, non significa che debba essere eseguito nella suite. (È possibile creare una categoria per "Problemi noti" e trattare tali test come un elenco di arretrati / TODO.)
Caleb,

Risposte:


17

Non mi piacciono gli unittest interrotti registrati perché producono rumore non necessario. Dopo ogni unittest avrei dovuto controllare tutti i problemi falliti (rosso). È rosso perché c'è un nuovo problema o perché c'è un vecchio aperto da fare / riparare. Questo non va bene se ci sono più di 20 unittest.

Invece io uso

  • [Ignore("Reason")]attributo che rende il risultato giallo o
  • throw new NotImplementedException()ciò rende il risultato grigio

Nota: sto usando NUnit per .net. Non sono sicuro che la funzione "grigia" sia presente in altri framework unittest.

Quindi mi piace il seguente significato dei risultati dei test unitari.

  • verde: tutto finito
  • grigio: nuove funzionalità pianificate che devono essere eseguite ma con priorità bassa
  • giallo: bug non ancora corretti. Dovrebbe essere risolto presto
  • rosso: nuovi bug. Dovrebbe essere risolto immediatamente

Tutto tranne "rosso" può essere registrato.

Per rispondere alla domanda: c'è più danno che valore nel check-in "test falliti in rosso" ma il check-in in "test ignorati in giallo" o "test in grigio NotImplementedYet" può essere utile come elenco di cose da fare.


il problema che vedo con questo approccio è che i test ignorati probabilmente non verranno mai risolti. Potresti anche rimuovere l'intero codice di prova, quale sarebbe la differenza (sto diventando un po 'arrogante qui)
Lovis

4
will probably never be fixedè una decisione politica se si desidera spendere efford in test automatici o meno. Con "test ignorati" hai la possibilità di risolverli. Eliminare i "test ignorati" significa "abbandonare i test automatici prima o poi fino a quando non ce ne sono più"
k3b

8

Non pretendo che si tratti di uno standard del settore, ma controllo i test non funzionanti per ricordare a me o agli altri membri del mio progetto che c'è ancora un problema con il codice o il test unitario stesso.

Suppongo che una cosa da considerare sia se le vostre politiche di sviluppo consentono test falliti senza penalità. Ho un amico che lavora in un negozio che fa lo sviluppo guidato dai test, quindi iniziano sempre con test falliti ...


5
Ma non dovresti mai effettuare il check-in in un test non riuscito, poiché il tuo server di compilazione non dovrebbe creare un progetto con un test interrotto.
CaffGeek

@Chad: la costruzione e il collaudo sono due parti separate di una fase automatizzata. La costruzione assicura che tutto si compili. Il test garantisce che il risultato della compilazione sia valido. La mia interpretazione della domanda non era: "dovrei controllare il codice che non viene compilato?" Invece è stato "dovrei fare il check-in in un test che so che fallirà?"
Unholysampler,

1
Stavo solo aggiungendo un punto da considerare, alcuni server di build a integrazione continua eseguono i test e, se falliscono, non vengono distribuiti. Giustamente, come se la compilazione fallisse, il codice fallisce e non ha senso distribuire un prodotto noto per essere rotto.
CaffGeek

@Chad: giusto, mi sono completamente dimenticato dei server CI. Questo sarebbe sicuramente un punto da considerare. Vale anche la pena chiarire cosa intendiamo con test "rotti"; sono semplicemente test "cattivi" o il test fallisce perché l'API è cambiata in qualche modo?
Tieson T.

La domanda avrebbe dovuto essere più chiara. Dovrebbe essere il test verrà compilato, ma il risultato previsto non riuscirà.

6

I test unitari non riusciti danno al team di sviluppo visibilità su ciò che deve essere fatto per conformarsi alle specifiche concordate.

In breve, i test unitari falliti danno alla squadra un elenco "TODO".

Per questo motivo, i test unitari falliti sono molto meglio di nessun test unitario. *
L'assenza di test unitari lascia il team di sviluppo al buio; le specifiche devono essere ripetutamente confermate manualmente .

[* A condizione che i test unitari in realtà testino qualcosa di utile.]


2
Esistono modi migliori per mantenere un elenco di cose da fare, ad esempio una lavagna, un'app di elenchi di cose da fare o un sistema di tracciamento dei problemi. È molto più facile utilizzare una suite di test se si prevede che passi sempre completamente e qualsiasi errore di test che appare è quindi un nuovo problema da risolvere immediatamente.
bdsl,

6

Lo scopo dei test unitari è affermare il comportamento previsto di un sistema, non documentare i difetti. Se utilizziamo i test unitari per documentare i difetti, l'utilità di questi per asserire il comportamento previsto viene ridotta. La risposta alla domanda "Perché questo test ha fallito?" non è un semplice "Oh, qualcosa è rotto che non mi aspettavo di essere rotto". Non è noto se il test fallito è previsto o imprevisto.

Ecco un paragrafo dall'inizio del capitolo 13 di Lavorare in modo efficace con il codice legacy :

I test di unità automatizzati sono uno strumento molto importante, ma non per la ricerca di bug - non direttamente, almeno. In generale, i test automatici dovrebbero specificare un obiettivo che vorremmo raggiungere o tentare di preservare il comportamento che è già lì. Nel flusso naturale di sviluppo, i test che specificano diventano test che preservano . Troverai bug, ma di solito non la prima volta che viene eseguito un test. Trovi bug nelle esecuzioni successive quando cambi comportamento che non ti aspettavi.


3

Ma quelli rotti che identificano i bug in un nuovo progetto, chiamato come tale. In questo modo puoi vedere che DOVREBBERO rompersi ... Man mano che vengono riparati, diventano verdi e si spostano nella normale suite di test.

NOTA: quel progetto dovrebbe essere impostato per non essere compilato sul server di compilazione, se il server di compilazione impedisce check-in che interrompono la compilazione (presupponendo che si definisca una compilazione interrotta come quella in cui tutti i test non vengono superati)


+1 anche se non c'è risposta se effettuare il check-in o meno c'è un argomento importante: build server
k3b

Preferirei usare un attributo per contrassegnare tale test invece di spostarlo in un progetto separato.
Codici A Caos

2

I test unitari dovrebbero verificare casi di errore oltre ai casi di successo di una funzione. Una funzione dovrebbe rifiutare esplicitamente input errati o disporre di documentazione per spiegare quali input sono considerati validi.

Se hai una funzione che non sta facendo nessuna di queste cose, è un bug e dovresti avere un modo per registrare che esiste. La creazione di un unit test che dimostra questo problema è un modo per farlo. La presentazione di un ticket bug è un'altra opzione.

Il punto del test unitario non è avere successo al 100%, il punto è trovare e correggere i bug nel codice. Non eseguire test è un modo semplice per avere successo al 100%, ma questo non è molto vantaggioso per il progetto.


Woah ... "Il punto del test unitario non è avere successo al 100%", stai dicendo che non tutti devono passare !?
CaffGeek

2
@Chad: Il punto è che è meglio avere test che sai falliranno, ma stanno dimostrando un vero problema invece di non avere il test solo in modo da poter avere il segno di spunta verde alla fine della build / test notturno.
Unholysampler,

8
@unholysampler, non ha mai superato i test, a meno che non siano contrassegnati CHIARAMENTE come "dovrebbero" rompere (facendo parte di un progetto diverso). Altrimenti, diventano rumorosi e non sai quando un test che dovrebbe passare è stato interrotto. Sconfigge completamente lo scopo dell'integrazione continua e avere UnitTest
CaffGeek

2
@Chad: penso che questo stia entrando nella semantica delle definizioni. Sulla base dell'OP, sembrava che stesse parlando della creazione di un test valido che esercita un bug. Tuttavia, il bug ha una priorità bassa e non è probabile che venga risolto immediatamente. Sei tu che hai introdotto l'integrazione continua, che pone restrizioni molto più severe sul processo automatizzato.
unholysampler il

4
@unholysampler, CI o no CI, il punto è che, quando esegui i test e sei abituato a vedere alcune luci rosse, ti abitui. Quindi, quando qualcosa che era verde, diventa rosso ... come fai a saperlo?!? È una pratica orribile e uno dei motivi per cui i test non vengono accettati in così tante organizzazioni.
CaffGeek,

1

File un bug per ogni errore e notare che nel risultato del test. Quindi, se riesci a mettere insieme il tuo atto e risolvi il bug, il test viene superato e lo elimini dal risultato del test. Non ignorare mai i problemi.


-3

Come vedo TDD fatto con l'implementazione dei test per un codice incompiuto è, scrivere prima i test con l'attributo [ExpectedException] o simile. Questo dovrebbe passare inizialmente poiché il codice incompleto non avrebbe alcuna logica e scrivere un nuovo codice Exception () in esso. Sebbene l'eccezione sia errata, ciò renderebbe i test inizialmente idonei per il check-in. Potremmo dimenticare un test ignorato ma potremmo sicuramente riordinare o riempire il codice incompleto. Quando lo facciamo, automaticamente il test corrispondente che si aspettava un'esclusione ora inizia a fallire e ti avvisa di risolverlo. Ciò può comportare una leggera alterazione del test per sbarazzarsi di ExpectException e invece fare affermazioni reali. CI, Dev, tester e clienti tutti contenti e una situazione vantaggiosa per tutti?


1
Questo non risponde alla domanda. Non si chiede cosa sia il TDD e perché testare le eccezioni previste.
Andy Wiesendanger,
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.