Come migliorare drasticamente la copertura del codice?

20

Ho il compito di ottenere un'applicazione legacy sotto test unitario. Prima un po 'di storia sull'applicazione: è un codice base RCP Java Java a 600k con questi problemi principali

  • massiccia duplicazione del codice
  • nessun incapsulamento, la maggior parte dei dati privati è accessibile dall'esterno, alcuni dati aziendali sono anche resi singletons quindi non è solo modificabile dall'esterno ma anche da qualsiasi luogo.
  • nessuna astrazione (ad esempio nessun modello di business, i dati aziendali sono archiviati in Object [] e double [] []), quindi nessun OO.

Esiste una buona suite di test di regressione e un efficiente team di QA sta testando e scoprendo bug. Conosco le tecniche su come ottenerlo testato dai libri classici, ad es. Michael Feathers, ma è troppo lento. Poiché esiste un sistema di test di regressione funzionante, non ho paura di ridefinire in modo aggressivo il sistema per consentire la scrittura dei test unitari.

Come dovrei iniziare ad attaccare il problema per ottenere rapidamente una copertura , quindi sono in grado di mostrare i progressi nella gestione (e in effetti iniziare a guadagnare dalla rete di sicurezza dei test JUnit)? Non voglio utilizzare strumenti per generare suite di test di regressione, ad es. AgitarOne, perché questi test non verificano se qualcosa è corretto.

    
posta Peter Kofler 20.11.2011 - 21:09
fonte

4 risposte

8

Credo che ci siano due assi principali lungo i quali il codice può essere inserito quando si tratta di introdurre i test unitari: A) quanto è testabile il codice? e B) quanto è stabile (cioè quanto urgentemente ha bisogno di test)? Guardando solo agli estremi, questo produce 4 categorie:

  1. Codice facile da testare e fragile
  2. Codice facile da testare e stabile
  3. Codice difficile da testare e fragile
  4. Codice difficile da testare e stabile

La categoria 1 è il punto di partenza più ovvio in cui è possibile trarre molti vantaggi con un lavoro relativamente ridotto. La categoria 2 ti consente di migliorare rapidamente la statistica di copertura (buona per il morale) e di acquisire maggiore esperienza con il codebase, mentre la categoria 3 è più (spesso frustrante) del lavoro ma offre anche maggiori benefici. Ciò che devi fare prima dipende da quanto sono importanti per te le statistiche sul morale e sulla copertura. Probabilmente la categoria 4 non vale la pena di preoccuparsi.

    
risposta data 21.11.2011 - 11:16
fonte
14

Ho molta esperienza di lavoro su sistemi legacy (non Java però), molto più grande di questo. Odio essere il portatore di cattive notizie, il tuo problema è la dimensione del tuo problema. Sospetto che tu l'abbia sottovalutato.

L'aggiunta di test di regressione al codice precedente è un processo lento e costoso. Molti requisiti non sono ben documentati - una correzione di bug qui, una patch lì, e prima che tu lo sai, il software definisce il proprio comportamento. Non avere test significa che l'implementazione è tutto ciò che c'è da fare, nessun test per "mettere alla prova" i requisiti impliciti implementati nel codice.

Se si tenta di ottenere una copertura rapidamente, è probabile che si affretti il lavoro, metà cottura e non riescono. I test forniranno una copertura parziale delle cose ovvie e una scarsa o nessuna copertura dei problemi reali. Convincerai gli stessi manager che stai tentando di vendere a quel Test unitario che non ne vale la pena, che è solo un altro proiettile d'argento che non funziona.

IMHO, l'approccio migliore è quello di scegliere come target i test. Utilizza metriche, analisi del registro delle imperfezioni e dei difetti per identificare l'1% o il 10% del codice che produce la maggior parte dei problemi. Colpisci duro questi moduli e ignora il resto. Non cercare di fare troppo, meno è di più.

Un obiettivo realistico è "Poiché abbiamo implementato l'UT, l'inserimento dei difetti nei moduli sottoposti a test è sceso al x% di quelli non sotto UT" (idealmente x è un numero < 100).

    
risposta data 21.11.2011 - 10:01
fonte
2

Mi viene in mente questo dire di non preoccuparsi della porta della stalla quando il cavallo è già scappato.

La realtà è che non esiste un modo economicamente efficace per ottenere una buona copertura di test per un sistema legacy, certamente non in un breve lasso di tempo. Come ha detto MattNz, sarà un processo molto dispendioso in termini di tempo e, in ultima analisi, estremamente costoso. Il mio istinto mi dice che se provi a fare qualcosa per impressionare la gestione, probabilmente creerai un nuovo incubo di manutenzione perché cerchi di mostrare troppo troppo velocemente, senza comprendere appieno i requisiti che stai tentando di testare.

Realisticamente, una volta che hai già scritto il codice, è quasi troppo tardi per scrivere i test in modo efficace senza il rischio di perdere qualcosa di vitale. D'altra parte, si potrebbe dire che alcuni test sono migliori di nessun test, ma se questo è il caso, i test stessi devono dimostrare che aggiungono valore al sistema nel suo insieme.

Il mio suggerimento sarebbe di guardare quelle aree chiave in cui senti che qualcosa è "rotto". Con ciò intendo che potrebbe essere un codice terribilmente inefficiente, o che è possibile dimostrare che è stato precedentemente costoso da mantenere. Documenta i problemi, quindi usalo come punto di partenza per introdurre un livello di test che ti aiuti a migliorare il sistema, senza intraprendere un enorme sforzo di reingegnerizzazione. L'idea qui è di evitare di recuperare il ritardo con i test, e invece di introdurre test per aiutarti a risolvere problemi specifici. Dopo un periodo di tempo, verifica se è possibile misurare e distinguere tra il costo precedente della manutenzione di quella sezione di codice e gli sforzi attuali con le correzioni applicate con i test di supporto.

La cosa da ricordare è che i dirigenti sono più interessati al rapporto costi / benefici e al modo in cui ciò influenza direttamente i loro clienti e, in definitiva, il loro budget. Non sono mai interessati a fare qualcosa semplicemente perché è la cosa migliore da fare a meno che tu non possa provare che fornirà loro un beneficio che è di loro interesse. Se sei in grado di dimostrare che stai migliorando il sistema e ottieni una buona copertura di test per il lavoro che stai facendo attualmente, è più probabile che la gestione sia considerata un'applicazione efficiente dei tuoi sforzi. Questo potrebbe permetterti di argomentare il caso di estendere i tuoi sforzi ad altre aree chiave, senza chiedere né un completo blocco dello sviluppo del prodotto, né tanto meno il quasi impossibile discutere di riscrittura!

    
risposta data 05.12.2011 - 08:53
fonte
1

Un modo per migliorare la copertura è scrivere più test.

Un altro modo è ridurre la ridondanza nel codice, in modo che i test esistenti in effetti coprano codice ridondante non attualmente coperto.

Immagina di avere 3 blocchi di codice, a, b, eb, dove b 'è una copia duplicata (esatta o near miss) di B, e che hai copertura su aeb ma non b' con test T .

Se refactoring del code base per eliminare b 'estraendo la commonality da b e b' come B, il code base ora appare come a, b0, B, b'0, con b0 contenente il codice non condiviso con b'0 e vice-versa, ed entrambi b0 e b'0 sono molto più piccoli di B e invocano / usano B.

Ora la funzionalità del programma non è cambiata, e nessuno dei due ha il test T, quindi possiamo eseguire di nuovo T e aspettarci che passi. Il codice ora coperto è a, b0 e B, ma non b'0. Il codice base è diventato più piccolo (b'0 è più piccolo di b '!) E copriamo ancora ciò che originariamente avevamo coperto. Il nostro indice di copertura è aumentato.

Per fare ciò, devi trovare b, b 'e idealmente B per abilitare il tuo refactoring. Lo strumento CloneDR può farlo per molte lingue, in particolare Java. Tu dici che il tuo codice base ha un sacco di codice duplicato; questo potrebbe essere un buon modo per affrontarlo a tuo vantaggio.

Stranamente, l'atto di trovare b e b 'spesso aumenta il tuo vocabolario sulle idee astratte che il programma implementa. Mentre lo strumento non ha idea di cosa fare b e b ', l'atto stesso di isolarli dal codice, permettendo una semplice messa a fuoco sul contenuto di b e b', spesso dà ai programmatori un'ottima idea di quale astrazione B_abstract gli strumenti del codice clonato . Quindi questo migliora anche la tua comprensione del codice. Assicurati di dare a B un buon nome quando lo estrai e otterrai una copertura di prova migliore e un programma più gestibile.

    
risposta data 05.12.2011 - 02:57
fonte

Leggi altre domande sui tag