Ti darò 2 esempi:
Una cosa banale, una volta ho visto una classe di rete che ti permetteva di impostare l'host e la porta e quindi inviare messaggi. Il test delle unità ha funzionato: è possibile impostare l'host, è possibile impostare la porta, è possibile chiamare il metodo che ha inviato messaggi.
Durante l'integrazione, qualcuno ha scritto il codice client che utilizzava questa classe e impostava la porta prima di impostare l'host. Nulla ha funzionato, perché il metodo host set ripristina la porta su un valore predefinito.
Questo è un esempio semplice e semplice che mostra che i test delle unità possono mostrare un comportamento corretto, ma poiché i metodi non sono stati chiamati nel modo previsto, non sono riusciti in fase di runtime. Si potrebbe obiettare che i test unitari non erano corretti, in quanto non testavano tutte le combinazioni delle chiamate di impostazione delle proprietà, ma il test unitario ha lo scopo di garantire che ogni sezione del codice funzioni correttamente (ad esempio imposta la proprietà corretta) e non come l'interazione tra quindi si verifica. (Ovviamente, sarebbe meglio sostenere che la classe avrebbe dovuto essere l'unità di test qui e che potrebbe aver catturato questo bug, ma anche così dubito che qualcuno avrebbe ripetuto il test con diverse combinazioni di setup di proprietà).
Un altro esempio è con il threading. Ho avuto una classe che ha funzionato perfettamente nei test di unità, ci vuole un blocco su una risorsa condivisa e chiama un metodo su un oggetto diverso, che come tale metodo viene deriso, ritorna immediatamente. Nel mondo reale, quel metodo in realtà fa molto più lavoro, crea un nuovo thread che aspetta che la stessa risorsa condivisa diventi disponibile, e quindi sblocca l'intero programma. Buona fortuna a trovarlo nei test unitari.
I test unitari non sono i test principali che dovresti fare. In effetti, se si dovesse avere solo un livello di test, sarebbe un test di integrazione. I test unitari sono un modo "veloce e sporco" di superare gli ovvi bug sollevati durante lo sviluppo e sono più di un controllo dello sviluppatore per assicurarsi di non aver fatto nulla di stupido (come quando ho scritto una classe aritmetica che è stata aggiunta quando hai chiamato l'operatore di sottrazione .. un test unitario avrebbe catturato quella piaga e incolla pigrizia). Questo è tutto ciò che dovrebbero essere lì per se, cercando di garantire un funzionamento perfetto del sistema che li utilizza è fuorviante.