posts - 452, comments - 1457, trackbacks - 139

Unit Testing, Dijkstra e i Community Days

Durante gli scorsi Community Days del 21 e 22 Giugno si è accesa una discussione riguardo ai Dynamic Languages ed in particolare al fatto che questi possano sopperire al problema dei Run-time errors con l'uso estensivo di Unit Testing.

Personalmente mi sono "acceso" a favore degli errori di compilazione che sono i miei migliori amici, scottato nel passato da brutte esperienze a base di variant, vbscript, javascript e memore del prezioso aiuto che invece il compilatore c++ mi ha sempre dato. Non nego per questo l'utilità dei linguaggi dinamici, per esempio per propositi di amministrazione di una rete al posto del più vetusto Windows Scripting Host, magari a fianco della nuova shell Monad.

La discussione ha toccato poi lo Unit Testing e ho "inutilmente" cercato di spiegare come ci siano innumerevoli casi in cui purtroppo sia totalmente inutile e impraticabile. Purtroppo ogni giorno ne ho un riscontro, per esempio solo una settimana dopo l'evento, grazie ad una segnalazione sui newsgroup, ho riscontrato un problema non identificabile con Unit Testing nella mia collection http://www.codeplex.com/RafCollection. Ho implementato il metodo EndNew in modo tale da lanciare una ArgumentOutOfRangeException per indici negativi ... sembra tutto ok e confortato da unit testing. Invece la GridView del Framework 2.0 chiama stranamente EndNew con index = -1 e lo Unit Testing si rivela ovviamente inutile.

Non per questo nego l'utilità di Unit Testing che in molti casi permette una validazione (che nulla ha a che fare con la dimostrazione di correttezza) del codice.

Odio le mode che vedono Unit Testing come panacea di tutti i mali e Edsger Dijkstra, uno dei padri degli algoritimi dell'ottimizzazione (che ricordo bene per aver implementato uno dei suoi algoritmi in C#) aveva già avvertito con un profetico “Program testing can be used to show the presence of bugs, but never to show their absence!”.

Print | posted on lunedì 2 luglio 2007 23.43 |

Feedback

Gravatar

# re: Unit Testing, Dijkstra e i Community Days

Sono pienamente d'accordo con te riguardo gli errori di compilazione e (come sai:) un po' meno riguardo i test. Hai ragione dicendo che gli unit test non risolvono tutti i problemi, è innegabile però che, nel caso in cui la base di test case aumenti con il tempo, cresca il grado di affidabilità del codice scritto.
A mio avviso si sottolinea sempre poco il fatto che nel caso si trovi un bug (come nel caso della tua geniale collection), sia importante scrivere un test per assicurarsi che il bug sia corretto e soprattutto che in futuro non ci siano regressioni. Se l'atteggiamento di fronte un bug è "ohhhh ma io pensavo che con gli unit test non potessero uscire bug...." ci sono dei seri problemi:P Scherzi a parte gli UT non autorizzano a sottovalutare l'importanza dei requisiti non funzionali di un sistema.
03/07/2007 9.44 | Gianluca Carucci
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

Tu parli di Unit Testing e non di TDD, quindi immagino intendi la scrittura dei test dopo la scrittura del codice per verificarne la funzionalità. Su questo non ho molta esperienza perchè sviluppo quasi esclusivamente in TDD.
Quello che ti posso dire è che i test non garantiscono l'assenza di bug, infatti, nei progetti che ho realizzato c'erano, ma riducono il tempo di risoluzione del bug in quanto il codice ha un design migliore e quindi è molto più semplice localizzare il bug. Inoltre utilizzo molto meno il debugger (molto meno non significa che non lo utilizzo diciamo un 80% di meno).
Fino ad ora non ho trovato ancora un caso di codice non testabile: ho sviluppato software in multithreading, con socket, db, ecc. e quindi per l'affermazione codice intestabile vorrei degli esempi concreti.
Infine ho provato alcuni frameword (NUnit, MbUnit, Quality Tools della Microsoft, ecc.) e per ora l'accoppiata migliore è MbUnit + TestDriven.NET per lanciare i test.
03/07/2007 10.00 | Antonio Ganci
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

Sinceramente non sono completamente d'accordo con te.
Cosa vuol dire che "esiste codice non testabile"? Non risesco ad immaginare un codice o un algoritmo che non sia testabile.
Sono d'accordo che i test non garantiscono che il codice sia esente da bug (nessuno può garantirlo), ma se ben scritti e mantenuti danno più garanzie e affidabilità nel tempo.
Ho letto un bel post tempo fa (non ricordo l'url) in cui si diceva che scrivere i test è come pagare in contanti: fai un piccolo sforzo adesso per avere più tranquillità domani, mentre non scrivere i test è come farsi prestare i soldi: ottieni tutto subito ma prima o poi devi pagare il debito.
Naturally IMHO
03/07/2007 11.29 | Emanuele DelBono
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

@Gianluca. Infatti non nego l'utilità dello unit testing ma non può essere lo strumento per determinare la correttezza di un algoritmo. È solo un punto di partenza durante le fasi di test.
Inoltre ci sono una montagna di casi in cui Unit Testing è molto più costoso di una procedura tradizionale (documentata si intende, non a casaccio secondo le bizze del developer).

@Emanuele. Per non testabile indtendo con unit testing. Cioè l'uso di questo strumento si rivela troppo oneroso quando lo si vuole automatizzazare. Come puoi testare le funzionalità di un designer??? A mano secondo una procedura scritta è il modo più sicuro (perché riproduce quello che farà l'utente) e produttivo (perché riprodurre un robot che simula il mouse non è coperto dal budget del cliente).

@Antonio. Non ho mai provato a lavorare sotto TDD e sono estremamente scettico che possa funzionare come generica metodologia di lavoro. Posso essere daccordo che in certi casi funzioni (e anche molto bene). Di qui a farne una metodologia per ogni tipo di progetto ce ne passa ...

Per quanto riguarda gli esempi, oltre a quello che citavo ad Emanuele, provo a fartene altri:
- custom control UI
- UI (abilitazione/disabilitazione controlli, tooltip, colori, etc.)
- conversione di formati. Attualmente ho appena finito la trasformazione da FlowDocument ad XHTML. A prescindere della conformità del formato finale ci sono tutta una serie di casistiche che vanno valutate sul file generato. Farlo in modo automatizzato implica la scrittura di un object model che validi il file con un dispendio inaccettabile (per il cliente) visto che parliamo di rifare (quasi) un browser ed inoltre non garantisce altro che poche casistiche.
- qualsiasi algoritmo che dipenda da una tecnologia di terzi. Ci sono casistiche non documentate (vedi librerie di creazione pdf) su cui solo la prova sul campo può darti un effettivo riscontro.
- constraint sulle performance. L'instrumentazione di una applicazione per misurare i tempi massimi accettabili è troppo invasiva e spesso inaccettabile per dare una validazione. Il test in questi casi deve essere fatto a mano senza instrumentazione.

Sono solo i primi che mi sono venuti in mente ma posso andare avanti se credi che non siano abbastanza calzanti ...


Comunque non nego l'utilità di unit testing che io stesso uso quando lo ritengo utile allo scopo. Ma non può essere (a mio avviso) lo strumento da cui partire tantomeno quello su cui firmi una conformità del software.

Quanto al debugger la tua diminuzione dell'80% sul suo uso mi fa pensare che tu scriva software algoritmicamente molto prevedibile. Evidentemente lavoriamo in campi abissalmente differenti. Per me è e rimane uno strumento insostituibile.
03/07/2007 11.40 | Raffaele Rialdi
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

Lo sto applicando in tutti i progetti da quattro anni a questa parte, l'unica differenza rispetto a prima è un tempo maggiore alla prima release, ma un grosso risparmio di tempo nella gestione delle modifiche risoluzione bug, ecc.
I casi che hai citato li ho affrontati in questa maniera:
- Pattern MVP: non testo i singoli clic del mouse, ma riduco al minimo il codice della view
- sulla conversione dovrei capire meglio, ho fatto diverse conversioni di formati senza dover "riscrivere" parser xml o browser
- Quanto si usa una libreria di terzi non la testo direttamente ma uso test di comportamento e non di stato
- Sulle performance dovrei capire meglio il tuo problema ho sviluppato software critici nelle performance, ma non ho avuto i problemi che dici
Non scrivo software prevalentemente algoritimico, gli unit test sono di due tipi:
- testo lo stato (la assert su un valore di una property, o il ritorno di un metodo, ecc.)
- testo il comportamento: tramite mock o stub che non testano il risultato di un algoritmo ma l'interazione di oggetti
03/07/2007 12.24 | Antonio Ganci
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

Volevo solo aggiungere:
Il TDD non è per me la soluzione di tutti i mali, ma uno strumento molto utile e non basta da solo a determinare il successo di un progetto.
Nel team dove ho lavorato e dove lavoro ho notato che non a tutti va bene come metodo di sviluppo (secondo me più un preconcetto che per un motivo veramente valido) ma credo che in futuro si diffonderà molto.
03/07/2007 12.30 | Antonio Ganci
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

Il tempo aggiuntivo sulla prima consegna non è un elemento da sottovalutare. Dipende dal cliente che hai.
- Il pattern MVP non risolve il testing di un custom control o di una interfaccia che abbia una validazione *grafica* complessa. Il test è strettamente dipendente dalla tecnologia (winform, wpf, etc.)
- Conversioni. Il risultato di una conversione di formato va al di là della validazione XML di XHTML. Ci sono le ben note differenze tra browser che non possono essere testate in modo automatizzato perché dipendono dal rendering del browser. Il risultato della conversione può inoltre essere più o meno efficiente e questo non puoi valutarlo in modo automatizzato (a costi accettabili)
La conversione (per esempio) in PDF è strettamente dipendente dalla libreria su cui ti appoggi che, per quanto sia ben documentata, ti costringe a sperimentare i risultati da ottenere.
- Test di comportamento. Se produci un output direttamente misurabile via codice, lo posso capire. Ma che fai quando la misurazione di quello che produci non è misurabile in modo semplice? (Audio, sfumatura di colori, formato in uscita che non puoi rileggere via codice per fare la verifica, o che è troppo costoso farlo)
- Performance. Un algoritmo può benissimo rispondere allo unit testing ed essere inutilizzabile perché è troppo lento. E spesso le misurazioni invasive (con counter, etc.) distorcono il vero risultato.
- Assert. Sono ottime e le uso ma veramente una goccia nel mare. Insufficienti a dare una garanzia su un metodo.
- I mock sono belli ma anche tanto pericolosi.

Se parli di applicazioni che leggono da db e mostrano quattro griglie posso capire che certi strumenti possano essere sufficientemente adeguati, ma grazie al cielo l'informatica non solo solo gestionali, altrimenti non farei questo mestiere :)
03/07/2007 14.34 | Raffaele Rialdi
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

Non posso che concordare con Emanuele e Antonio.
UNIT TESTING NON È SICURMANENTE LA PANACEA DI TUTTI I MALI.
Proprio ieri dicevo la stessa frase ad un collega a cui sto trasferendo il know-out per sviluppare in TDD.
Concordo anche sul fatto che testare a posteriori serve a molto poco.
Quando era un novizio di TDD pensavo anch'io che ci fossero molto casi in cui TDD
non fosse applicabile ma da quando uso mock e stub mi sono dovuto ricredere.
Per rendere ulteriormente efficace il TDD io abbino al framework di test (IMHO mbUnit)
anche altri strumenti per il controllo del codice vedi NCover per verificare la copertura dei test.
Con TDD si aumenta la complessità necessaria per produrre software in ma il codice prodotto è qualitativamente migliore del codice prodotto senza.
Come dice Ken Beck nel suo libro "Extreme Programming Explained" produrre codice in TDD e pair-programming migliora la qualità del codice prodotto.
Migliore qualità significa pochissimi bug, pochi bug significa risparmiare tempi.
Quindi pair e TDD sono solo all'apparenza approcci più dispendiosi di un approccio "senza metodi agili".
Inoltre all'aumentare della complessità dell'applicazione la gestione del cambiamento del software cresce in maniera esponenziale mentre con strumenti
di test automatici si può mantere entro un livello accettabile il costo di gestione del cambiamento.
Altro elemento fondamentale da non trascurare è la fiducia del committente.
Codice di qualità permette di raggiungere un'altro obbiettivo importate: guadagnare la fiducia del committente.
IMHO produrre codice in TDD alla fine PAGA.
Imparare a produrre codice con questo metodo necessita allenamento anche per i più esperti
perchè significa modificare il classico modo di approcciare al problema.
03/07/2007 14.55 | Maccari Claudio
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

Ancora una standing ovation per te! Mitico Raf!
03/07/2007 15.02 | Mario Duzioni
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

@Claudio. Che ti piaccia l'ho capito. Che su tanti bei libri si trovino belle parole a favore di metodologie, strategie, pattern e quant'altro fa parte della moda corrente e passi.
Ma a parte le rispettive convinzioni personali, non vedo in modo *pratico* come sia applicabile agli esempi che ho fatto (e sono solo alcuni).
Per *pratico* intendo che il vantaggio deve essere qualitativo ma anche di costi perché il cliente che paga vuole guarda il totale (che comprende certamente l'intero ciclo di vita del software, certamente comprensivo anche della manutenzione).

Ripeto per l'ennesima volta che non sto dicendo non sia utile Unit Testing, ma che non può essere una base per validare un software. È solo uno dei tanti sistemi che può rivelarsi più o meno utile a seconda dei casi.

@Mario. Ma c'è qualcuno che la pensa come me allora :)
03/07/2007 15.21 | Raffaele Rialdi
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

Raffaele io non lavoro molto su gestionali, fino all'anno scoro lavoravo in ambito Formula 1 e il software che producevamo girava ai box e quindi credimi che avevamo problematiche di performance e affidabilità non indifferenti. Tipo rendering di grafici complessi in realtime, analisi in tempo reale dei dati della macchina, ecc.
Ora lavoro in ambito finanziario e mi occupo dell'analisi dei dati di mercato e anche qui la parte che seguo è poco gestionale.
Sono applicazioni complesse sia dal punto di vista UI che algoritmico ed uso diverse librerie terze parti.
Ora dobbiamo metterci d'accordo su cosa intendiamo per test:
Quando realizzo il codice che visualizza un grafico, io NON testo i pixel che vanno a video, ma mi fermo a testare la chiamata di una routine che ad esempio disegna una line e di cui suppondo pragmaticamente che funzioni (visto che l'ha scritta la microsoft ;-)).
Se utilizzo una libreria terze parti ci accedo tramite wrapper prodotti da me e il testing si ferma a controllare che ho fatto una chiamata la quale poi si occuperà a sua volta di chiamare la libreria esterna, ecc.
Ci sono poi altri tipi di test differenti dagli unit test che non sempre si possono fare in automatico come i test di accettazione, usabilità, ecc.
Uno Unit Test deve essere il più indipendente possibile dal PC su cui gira nel senso che non deve dipendere da hardware specifico, file system o database.

03/07/2007 15.48 | Antonio Ganci
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

Finalmente qualcuno che fa qualcosa di diverso dal solito gestionale :)

Tracciare una riga solo perché le coordinate sono corrette non assicura affatto che il *risultato complessivo* sia quello voluto. In un controllo GDI hai il problema dell'erasebackground, delle paint sui contenitori (user control, panel, etc.) , del double-buffering. Ci sono test che devi effettuare guardando la trace di Spy++ e non puoi dare per scontato che la chiamata alla primitiva grafica sia la scelta migliore perché dipende dal contesto in cui la usi.
Il fatto di fermarsi a controllare se l'input verso la blackbox successiva sia corretta, non è sufficiente a garantire che il sistema nella sua interezza funzioni. Il funzionamento non gode della proprietà transitiva... se i sistemi A e B funzionano non necessariamente A+B funzionano insieme! Può valere per per alcuni sistemi ma non per tutti.

Sulla dipendenza dell'hardware specifico la scelta di cui parli è coerente con unit testing. Se però parliamo di performance il discorso non può fare a meno di essere specifico all'hardware... l'isolamento dalla tecnologia la otteniamo strutturando a layer l'applicazione che però in ogni suo componente deve essere molto ben conscia della tecnologia specifica che usa per sfruttarla al meglio (o evitarne i punti deboli).
03/07/2007 16.36 | Raffaele Rialdi
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

Iniziamo a convergere sono contento :)
Ti parlo di una problematica concreta che ho avuto: inzialmente i grafici li visualizzavo utilizzando le GDI+, ma la quantità di dati che dovevo visualizzare era tale che le performance erano troppo scarse (meno di un frame al secondo).
Allora ho sostituito le GDI+ con le vecchie GDI le quali hanno dato un miglioramento delle performance notevole.
Nell'applicazione questo cambiamento ha comportato relativamente poco lavoro, in pratica ho dovuto scrivere una classe che implementa un'interfaccia e i test non li ho toccati perchè si fermavano alla chiamata dei metodi dell'interfaccia.
Con ciò voglio dire che Spy++, ecc. sono strumenti che ancora uso, ma che esulano dallo unit test secondo il mio punto di vista.
A volte dopo aver scritto tutti i test mi capita di lanciare l'applicazione la quale non fa assolutamente nulla perchè mi sono dimenticato di far partire, per esempio, l'evento Click dalla view.
Quindi lo unit test non garantisce che l'applicazione funzioni senza bug, ma aiuta a scrivere classi con basso accoppiamento e alta coesione.
Non dico che senza unit test questo non sia possibile, ma per quanto mi riguarda se non scrivo i test corro il rischio di cadere in tentazione :-)
Sono molto pragmatico nella scrittura del software e non credo ASSOLUTAMENTE nel silver bullet.


03/07/2007 16.53 | Antonio Ganci
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

Concordo con te sui Dynamic Languages.

Non concordo su 2 cose che dici a proposito degli unit test:

- il primo obiettivo degli unit test è guidare l'emersione del disegno, il secondo è scovare errori di programmazione (hanno successo se evidenziano un bug) ; nessuno ha mai preteso di usarli per dimostrare che non ci sono bug

- quando parli di validazione ti confondi, la validazione risponde alla domanda "Abbiamo realizzato il software giusto?" cioè soddisfa i bisogni per cui è stato commissionato . Invece i test hanno a che fare con la verifica che risponde alla domanda "Abbiamo realizzato bene il software?" cioè è aderente ai requisiti

03/07/2007 16.57 | Luca Minudel
Gravatar

# TDD, UnitTesting ed il significato di

03/07/2007 17.54 | TheDuzBlog! ;-p
Gravatar

# TDD, UnitTesting ed il significato di

03/07/2007 17.57 | TheDuzBlog! ;-p
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

@Antonio. Cominciamo a convergere sul serio ... quello che scrivi mi trova concorde.
Sul guadagno dell'isolamento dei layer non ci sono dubbi ma questo prescinde dal fatto di lavorare in TDD, in modo tradizionale o qualsiasi altra metodologia.

Nel silver bullet non ci credo ovviamente neanch'io ma il discorso era proprio nato dal fatto che Unit Testing viene visto come sistema per controbilanciare ai più frequenti errori di runtime dei linguaggi dinamici... cosa a cui ovviamente non credo nel modo più assoluto.

@Luca
- purtroppo come ho scritto ad Antonio durante i community days veniva indicata come strada l'uso di unit testing per contrastare gli errori di runtime che inevitabilmente arrivano per l'assenza del controllo di errori da parte del compilatore. Quindi il "nessuno" che scrivi in realtà è "qualcuno".
- il disegno può essere guidato da un test solo se il test è realizzabile. Il disegno può essere anche evidenziato in altro modo.
Se il test è realizzabile, allora è una questione di scelta e gusto personale. Se non è realizzabile, diventa una scelta diabolicamente errata.

- Mi sembra che sulla validazione stiamo parlando della stessa cosa. Non concordo invece sulla definizione dello unit testing:
- unit testing *in alcuni casi* permette una validazione funzionale del singolo componente ma NON di correttezza del software nella sua interezza.
Per affermare la correttezza del software è necessario che vi sia la funzionalità complessiva data non solo dal corretto funzionamento di tutti i componenti del sistema ma anche dal fatto che collaborino tra loro. Antonio prima con il mancato collegamento del click del bottone alla funzionalità, ha fatto un esempio lampante.
03/07/2007 18.07 | Raffaele Rialdi
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

dici

> - unit testing *in alcuni casi* permette una validazione funzionale del singolo componente ma NON di correttezza del software nella sua interezza.

ok, il test che prova una singola feature per l'utente è l'acceptance testing e non lo unit testing , due strumenti che si usano insieme non in contrapposizione

dici

> Se il test è realizzabile, allora è una questione di scelta e gusto personale. Se non è realizzabile, diventa una scelta diabolicamente errata.

è proprio quando lo _unit_ test non è realizzabile che c'è l'indizio di un cattivo disegno e questA è la prima utilità di unit testing.

sul fatto che gli unit testing non bastano/servono ad eliminare l'utilità del compilatore e che i linguaggi dinamici hanno un contesto di utilità che non è affatto quello della produzione industriale di software applicativo commerciale non ci sono dubbi, sono con te al 100%

è un dibattito che nell'informatica è stato risolto 50 anni fa, che l'esperienza dei linguaggi di scripting durante la bolla delle dot com ha reso evidente nella pratica . cmq se qualcuno vuole spararsi sui piedi ... pperché sudare x impedirglielo? basta starci distante ;-)

03/07/2007 18.28 | Luca Minudel
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

Luca,
- dimentichi non sono io che dico che lo unit testing non è uno strumento completo. Il test di funzionalità di un requisito sono il primo a dire che è ben altra cosa ed è indispensabile.

- ho già fatto molti esempi negli altri post in cui lo unit testing non è possibile e infatti con Antonio siamo arrivati ad una convergenza. Qui il design non c'entra nulla, è semplicemente impossibile o non conveniente fare unit testing automatizzato su certe funzionalità.

- si certo, ci starò lontano a chi si spara sui piedi :) ... ma di fatto sui linguaggi dinamici c'è un gran fermento. Io ne riconosco i pregi in certi campi di applicazione ma c'è chi pensa di farne uno strumento primario e come ho già detto non concordo. IMHO è una questione di mode.
03/07/2007 18.54 | Raffaele Rialdi
Gravatar

# Unit testing non

03/07/2007 21.09 | makka
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

Abbasso un attimo i toni della conversazione...
non è che tra qualche tempo ci troveremo tutti a rifare mille discorsi paralleli quelli che l'umanità ha già affrontato riguardo al metodo scientifico con proposizioni tipo: se non puoi realizzare un programma in grado di falsificare il tuo codice con dei bug allora il tuo non è vero codice! Oppure il tuo codice è vero codice solo perchè non è ancora stato scritto un codice che approssima meglio la soluzione del problema!... e via di questo passo...
...si ok mi rimetto all' ombra che il sole mi fa male evidentemente.... :)
ciao e buone vacanze a tutti!

20/07/2007 15.38 | Stefano Padovan
Gravatar

# re: Unit Testing, Dijkstra e i Community Days

Ciao Stefano,
mi piace solo valutare in modo critico (nel vero senso del termine) ciò che viene considerata pratica consolidata e indiscutibile.
Tante volte anche nel nostro mestiere certe cose diventano moda e come tali non c'è neppure il coraggio di criticarle.

Da parte mia c'è solo la voglia di tenere un equilibrio facendo tesoro delle esperienze acquisite, tutto qui.
30/07/2007 23.07 | Raffaele Rialdi

Post Comment

Title  
Name  
Email
Url
Comment   
Please add 8 and 5 and type the answer here:

Powered by: