Come viene misurata la copertura del codice?

1

Per molte lingue ci sono vari strumenti che misurano la copertura del codice. Ma come funziona esattamente?

Ho alcune idee, come potrebbe funzionare:

Gli strumenti di copertura eseguono semplicemente il codice nel debugger e lo attraversano? Viene utilizzata una sorta di analisi statica? Oppure alcuni strumenti semplicemente inseriscono alcuni indicatori nel codice sorgente, che vengono richiamati quando il codice viene esercitato? Immagino anche che in alcuni casi la piattaforma fornisca strumenti per misurare la copertura a un livello inferiore.

    
posta Finn Poppinga 16.02.2018 - 23:00
fonte

2 risposte

4

Gli strumenti di copertura del codice funzionano in due versioni:

  • il codice è instrumented per registrare le statistiche di copertura o
  • il programma viene eseguito con un meccanismo debugger o profiler o tracing .

La misurazione della copertura è uno strumento di garanzia della qualità dinamico , poiché misura quale codice è eseguito . L'analisi statica non è sufficiente.

Se è disponibile un debugger, è facile interrompere l'esecuzione normale dopo ogni istruzione e registrare quella dichiarazione come coperta. Tuttavia, tutte queste interruzioni arrivano a un notevole runtime, il che rallenta i test. Gli strumenti di copertura basati su debugger sono spesso limitati dalle interfacce di debug in quali tipi di copertura possono essere raccolti. Per esempio. potresti non essere in grado di raccogliere la copertura delle filiali all'interno di espressioni come bar() && baz() .

La strumentazione viene eseguita dal compilatore o da una fase di post-compilazione per iniettare il codice nell'eseguibile che registra la copertura. Il codice sorgente non è stato modificato. Questo ha un sovraccarico di runtime inferiore rispetto a una soluzione basata su debugger, ma richiede la compilazione del programma in una modalità di raccolta di copertura speciale.

Ad esempio, lo strumento python coverage.py utilizza gli hook di traccia incorporati di Python. Al contrario, GCC e Clang supportano la raccolta di copertura basata sulla strumentazione durante la compilazione con i flag -fprofile-arcs -ftest-coverage (è necessario disabilitare anche le ottimizzazioni e utilizzare un build di debugging: -g -O0 ). Il vantaggio nella raccolta della copertura del ramo: il compilatore conosce tutti i rami presenti nel codice macchina, non solo i rami facilmente visibili nel codice sorgente. Quando il programma viene eseguito, registrerà la copertura in un file che può essere massaggiato in report con strumenti come gcov, lcov, gcovr e molti altri. (Divulgazione: mantengo gcovr.)

In generale, la misurazione della copertura richiede lo stesso tipo di dati di un profiler. Spesso, questi strumenti utilizzano esattamente la stessa infrastruttura. Tuttavia, un profiler può permettersi di essere meno preciso poiché i punti caldi verranno eseguiti spesso. A differenza degli strumenti di copertura, possono utilizzare campionamento per misurare la frequenza con cui viene eseguito il codice. Un profiler di campionamento interrompe regolarmente il processo e raccoglie una traccia di stack che punta alla posizione corrente. Questo accade meno spesso di ogni affermazione, spesso solo ogni pochi millisecondi. Quindi hanno un impatto minore sulle prestazioni, ma i loro dati sono meno precisi.

    
risposta data 16.02.2018 - 23:28
fonte
1

Dipende.

Per i linguaggi compilati, in genere si utilizza il supporto del compilatore, ad esempio il compilatore aggiunge istruzioni aggiuntive che aumentano i contatori per riga. (O meglio, per blocco senza rami.)

Per linguaggi compilati just-in-time, vale la stessa cosa, anche se per lo più sarebbe il compilatore JIT che inserisce le istruzioni extra.

Negli ambienti interpretati, l'interprete potrebbe fornire un'interfaccia per i profiler per ottenere informazioni.

    
risposta data 16.02.2018 - 23:07
fonte

Leggi altre domande sui tag