Test unitario per una biblioteca informatica scientifica

12

Ho avuto un po 'di esperienza con i test unitari prima, in quello che chiamo (non peggioratamente) il classico progetto di ingegneria del software: un MVC, con una GUI utente, un database, una logica di business nel livello intermedio, ecc. Ora sto scrivendo una libreria informatica scientifica in C # (sì, so che il C # è troppo lento, uso C, non reinventare la ruota, e tutto il resto, ma abbiamo un sacco di persone che fanno calcoli scientifici nella mia facoltà in C #, e abbiamo bisogno di esso). È un piccolo progetto, in termini di sviluppo del software, perché lo scrivo principalmente da solo, e di volta in volta con l'aiuto di alcuni colleghi. Inoltre, non sono pagato per questo e, cosa più importante, è un progetto accademico. Voglio dire, mi aspetto che un giorno abbia qualità professionale, perché sto programmando di diventare open source, e spero che con abbastanza tempo crescerà una comunità di sviluppatori.

Ad ogni modo, il progetto sta diventando grande (circa 18.000 righe di codice, che penso siano grandi per un progetto di un uomo), e il suo uscire dalle mie mani. Sto usando git per il controllo del codice sorgente, e penso di essere andato tutto bene, ma sto testando come una vecchia scuola, intendo scrivere applicazioni per console complete che testano gran parte del sistema, principalmente perché non ho idea di come fare test unitari in questo scenario, anche se sento che è quello che dovrei fare. Il problema è che la libreria contiene principalmente algoritmi, ad esempio algoritmi di grafici, classificatori, risolutori numerici, distribuzioni casuali, ecc. Io non so come specificare minuscoli casi di test per ciascuno di questi algoritmi e poiché molti di essi sono stocastico non so come convalidare la correttezza. Per la classificazione, ad esempio, ci sono alcune metriche come precisione e richiamo, ma queste metriche sono migliori per confrontare due algoritmi che per giudicare un singolo algoritmo. Quindi, come posso definire la correttezza qui?

Infine c'è anche il problema delle prestazioni. So che è un insieme di test completamente diverso, ma le prestazioni sono una delle caratteristiche importanti di uno strumento scientifico, piuttosto che la soddisfazione dell'utente o altre metriche di ingegneria del software.

Uno dei miei maggiori problemi è con le strutture dati. L'unico test che riesco a trovare su un albero di kd è uno stress test: inserisci un sacco di vettori casuali e poi esegui molte query casuali e confronti con una ricerca lineare ingenua. Lo stesso per le prestazioni. E con gli ottimizzatori numerici, ho delle funzioni di benchmark che posso testare, ma poi di nuovo, questo è uno stress test. Non penso che questi test possano essere classificati come test unitari e, cosa più importante, funzionano continuamente, poiché la maggior parte di essi è piuttosto pesante. Ma penso anche che questi test debbano essere fatti, non posso semplicemente inserire due elementi, inserire la root e sì, funziona per il caso 0-1-n.

Quindi, qual è l'approccio di test (unitario) per questo tipo di software? E come organizzo i test unitari e quelli pesanti attorno al ciclo code-build-commit-integration?

    
posta Alejandro Piad 26.02.2013 - 14:42
fonte

1 risposta

16

Direi che il calcolo scientifico è in realtà abbastanza adatto per i test unitari. Disponi di input e output precisi, pre e post-condizioni chiaramente definite che probabilmente non cambieranno a settimane alterne secondo il capriccio di alcuni designer e senza requisiti di UI difficili da testare.

Hai nominato alcuni elementi che potrebbero causare problemi; ecco cosa fare su di loro:

  • algoritmi randomizzati: ci sono due possibilità. Se in realtà si desidera testare la randomizzazione stessa, è sufficiente pianificare un numero elevato di ripetizioni e affermare che la proporzione prevista di casi soddisfa il criterio desiderato, con margini di errore sufficientemente grandi che i fallimenti dei test spuri saranno piuttosto rari. (Una suite di test che segnala in modo inaffidabile bug fantasma è molto peggiore di quella che non cattura tutti i difetti immaginabili.) In alternativa, usa una sorgente casuale configurabile e sostituisci l'orologio di sistema (o qualunque cosa tu usi ) con una fonte deterministica tramite l'iniezione di dipendenza in modo che i test diventino completamente prevedibili.
  • algoritmi definiti solo in termini di precisione / richiamo: nulla ti impedisce di inserire un intero set di casi di input e misurare precisione e richiamo aggiungendoli tutti; è solo questione di generare semi-automaticamente questi casi di test in modo efficiente, in modo che fornire i dati di test non diventi il collo di bottiglia della tua produttività. In alternativa, specificare alcune coppie input / output scelte con giudizio e affermare che l'algoritmo calcola esattamente l'input desiderato può funzionare anche se la routine è abbastanza prevedibile.
  • requisiti non funzionali: se le specifiche forniscono davvero requisiti spazio / temporali espliciti, in pratica hanno per eseguire intere suite di coppie input / output e verificare che l'utilizzo delle risorse sia conforme a approssimativamente al modello di utilizzo richiesto. Il trucco qui è di calibrare prima la propria classe di test, in modo che non si misurino dieci problemi con dimensioni diverse che finiscono per essere troppo veloci da misurare, o che richiedono così tanto tempo che l'esecuzione della suite di test diventa poco pratica. Puoi perfino scrivere un piccolo generatore di casi d'uso che crea casi di test di dimensioni diverse, a seconda della velocità con cui l'unità di elaborazione è in esecuzione.
  • test di esecuzione rapida e rallentata: che si tratti di test di unità o di integrazione, spesso si ottengono molti test molto rapidi e alcuni molto lenti. Poiché eseguire regolarmente i test è molto prezioso, di solito passo alla via pragmatica e separo tutto ciò che ho in una suite veloce e lenta, in modo che il più veloce possa essere eseguito il più spesso possibile (sicuramente prima di ogni commit), e non importa se due test "semanticamente" appartengono o no.
risposta data 26.02.2013 - 15:07
fonte

Leggi altre domande sui tag