Code coverage – pokrycie kodu
Transkrypt
Code coverage – pokrycie kodu
Piotr Dwieczkowski
Code coverage
Mierzenie pokrycia kodu, teoria oraz praktyka w C/C++
Plan
Co to jest pokrycie kodu?
Możliwe sposoby wykorzystania
Rodzaje statystyk
Wady i zalety mierzenia porycia kodu
Narzędzia: gcov, lcov
Bardzo prosty przykład
Bardziej skomplikowane – CMAKE + gcov + lcov
Alternatywy
Co to jest pokrycie kodu?
Miara wykorzystywana przy testowaniu
oprogramowania
Opisuje w jakim stopieniu program został
sprawdzony przez testy
Zazwyczaj wykorzystywane przy określaniu
‘skuteczności’ testów jednostkowych
Dla większości języków istnieją zestawy narzędzi do
testowania/pomiaru pokrycia
Pokrycie możemy mierzyd według różnych kryteriów
Pokrycie linii kodu
ang. statement/line coverage
Dla każdej linii kodu – czy instrukcje w danej linii
zostały uruchomione?
Zależne od struktury tekstowej kodu, np. :
if( 1 == 0 ) printf(“hello world!”);
Ta linia zawsze zostanie oznaczona jako uruchomiona
Nie da nam to żadnej informacji o pokryciu printf
Mało nam mówi o pętlach i instrukcjach warunkowcyh
Pokrycie funkcji
ang. function coverage
Dla każdej funkcji – czy została wykonana?
Pozwala szybko znaleźd funkcje, które nie są
przetestowane
Lub np. nie są już używane
Może byd przydatne przy prostym profilowaniu
jeśli
zbieramy liczbę wywołao
w tym wypadku najlepiej zbierad czas spędzony w
funkcji (gprof)
Pokrycie gałęzi
ang. branch/decision coverage
Wymaga analizy struktury kodu
Mierzy czy instrukcje warunkowe wykonały obie
ścieżki kodu (także pętle)
Dokładniej – mierzy czy wartośd logiczna warunku
została wyliczona podczas uruchomienia jako
prawda i fałsz
Nie bierze pod uwagę w jaki sposób została ona
wyliczona (ang. condition coverage)
Pokrycie ścieżek
ang. path coverage
Mierzy pokrycie wszystkich możliwych ścieżek
wykonania funkcji
Oczywiście pętle to utrudniają
Możemy
wprowadzid dodatkowe kryteria
Zamiast nieskooczonej liczby ścieżek pętla dodaje dwie:
Program nie
wszedł do pętli
Program wszedł do pętli (i uruchomił ją dowolną liczbę razy)
Inne kryteria
Race coverage
Condition coverage (Multiple condition coverage)
Loop coverage
Data flow coverage
Relational operator coverage
Weak mutation coverage
…
Pokrycie kodu - wady, zalety
Dobry sposób oceniania skuteczności testów
Tworzenie testów dla pokrycia wymusza dodatkową
analizę kodu
Dużo (raczej łatwych w obsłudze) narzędzi
Nie istnieje idealna miara pokrycia
Nie można w 100% wierzyd, że wszystko zostało sprawdzone
Wykonianie i analiza części z opisanych kryteriów może zająd
dużo czasu
Z drugiej strony – nie zawsze opłaca się dążyd do 100%
pokrycia
Prawo malejących przychodów (ang. dimnishing returns)
gcov
Pozwala analizowad pokrycie linii kodu,
wykonywanych funkcji oraz gałęzi
Wchodzi w skład pakietu gcc, działa tylko z
programami skompilowanymi przez gcc (wymaga
specjalnych flag)
Dla podanego pliku źródłowego nazwa.cpp
generuje tekstowy plik nazwa.cpp.gcov zawierający
informacje o pokryciu dla każdej linii
Jest raczej nieprzyjemny w obsłudze – trudno go
ręcznie używad przy nieco większych projektach
Pliki .gcov
(wygenerowane przez gcov –b)
-:
0:Source:tmp.c
-:
0:Graph:tmp.gcno
-:
0:Data:tmp.gcda
-:
0:Runs:1
-:
0:Programs:1
-:
1:#include <stdio.h>
-:
2:
-:
3:int main (void)
function main called 1 returned 1
blocks executed 75%
1:
4:{
1:
5: int i, total;
-:
6:
1:
7: total = 0;
-:
8:
11: 9: for (i = 0; i < 10; i++)
branch 0 taken 91% (fallthrough)
branch 1 taken 9%
10: 10:
total += i;
-:
11:
1:
12: if (total != 45)
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
#####:13:
printf ("Failure\n");
call
0 never executed
-:
14: else
1:
15:
printf ("Success\n");
call
0 called 1 returned 100%
1:
16: return 0;
-:
17:}
Jak to działa?
Podczas kompilacji podajemy do gcc odpowiednie flagi:
–fprofile–arcs –ftest–coverage
Gcc generuje pliki .gcno dla każdego pliku źródłowego
Oprócz tego do programu jest dołączany kod, który sprawia, że:
Zawierają one informacje o strukturze kodu
Podczas działania zbierane są statystyki pokrycia
Przed zakooczeniem programu dane są zapisywane w plikach .gcda (w
tym katalogu, w którym jest plik .gcno)
Każdemu plikowi źródłowemu odpowiada po jednym .gcda i .gcno
(ale nie plikom nagłówkowym)
Pomimo tego przy uruchomieniu gcov generuje pokrycie dla plików
nagłówkowych
Pliki .gcda i .gcno są binarne i są wykorzystywane przez np. gcov, gprof i
inne programy z gcc
Problemy
Nie możemy ustalid gdzie gcc zapisuje plik .gcno i
.gcda (zapisuje tam gdzie plik wyjściowy)
gcov musi zostad uruchomiony z tego samego
katalogu co gcc podczas kompilacji
Można podpowiedzied gdzie gcov ma szukad plików
lcov
Front-end do gcov
Pozwala na generowanie stron html z informacjami o
pokryciu dla poszczególnych plików
Dużo łatwiejszy w obsłudze – wystarczy podad katalog,
a lcov znajdzie pliki .gcda i .gcno (także w
podkatalogach) i dla każdego pliku źródłowego
przeanalizuje pokrycie
lcov zapisuje pokrycie dla całego katalogu w
pojedynczym pliku tracefile.info
genhtml zamienia plik .info w pliki html
lcov – możliwości
W jednym pliku .info mogą byd przechowywane
informacje o różnych uruchomieniach
Można przeglądad pokrycie według oddzielnie
uruchomionych testów
lcov umożliwia np. porównywanie uruchomieo
dodatkowo: lcov został stworzony w celu analizy
pokrycia kodu uruchomionego jądra Linux (w czasie
rzeczywistym)
gcov+lcov - tutorial
Kompilacja z flagami gcc/g++
g++ –fprofile–arcs –ftest–coverage main.cpp –o main
Zauważ utworzone pliki .gcno
Uruchom program tak jak zwykle
./main
Zauważ pliki .gcds
Jeśli używasz bezpośrednio gcov
gcov plik_zrodlowy.cpp (albo *.cpp)
Dla każdego pliku źródłowego otrzymujemy plik .cpp.gcov
Jeśli używasz lcov
uruchom lcov (najlepiej w oddzielnym katalogu) i wygeneruj html
mkdir report
cd report
lcov --capture --directory ../ --output-file main.info
c++filt < main.info > main.info (czytelne nazwy np. funkcji)
genhtml main.info
Otwórz index.html w ulubionej przeglądarce
Złożony przykład – CMAKE
Należy
dodad flagi kompilatora – CMAKE tego nie
ułatwia (ze względu na przenośnośd)
Mamy zmienną CMAKE_CXX_COMPILER_FLAGS
Możemy ją
zmieniad w zależności od wartości opcji
Wystarczy zrobid to raz dla całego projektu (zmienid flagi
przed dodawaniem podfolderów)
Wykonujemy
make bez pokrycia, potem z pokryciem
Nic się nie dzieje – CMAKE nie wie, że gcc powinien
wygenerowad pliki .gcno – nie szuka ich i nie wie, że
należy przebudowad projekt
Złożony przykład – Testowanie
UnitTest++ – wybrany na podstawie analizy dyskusji na
SO i kilku artykułów w sieci
W łatwy sposób można tworzyd całe zestawy testów
Można też używad CTest
Może byd to zbyt duże narzędzie dla niewielkich projektów
Nie zdążyłem przetestowad tego rozwiązania
Złożony przykład – Generowanie pokrycia
Próby dodania gcov jako TARGET w Makefile
żeby można było uruchomid make coverage
taki TARGET można zdefiniowad jako obowiązkowy krok po
testach
zarówno add_custom_target jak i add_custom_command
nie spełniają wszystkich wymagao
trudno dostad się do plikó w.gcno
powinny byd w katalogu CMakeFiles/target_name.dir/
ale nie jest to zdefiniowane w żadnej stałej co oznacza, że
może się zmienid (znowu ze względu na przenośnośd)
Generowanie pokrycia – rozwiązanie
lcov służy właśnie do tego (i np. omija generację
plików .gcov)
Innym rozwiązaniem może byd CTest (w
dokumentacji jest wspomniana opcja generowania
pokrycia)
Alternatywy
Działające z gcc:
ggcov
Trucov
gcc
pod cygwin
Visual Studio 2008/10
Testowanie/pokrycie wbudowane
wersji
Linux/Windows – BullseyeCoverage
CTC++ TestCoverage
Urządzenia wbudowane
Jest to możliwe, ale nie ma dużo materiałów
O gcov+arm jest trochę informacji na grupach
dyskusyjnych
Jest też praca “Gcov on an embedded systems
Skupia
się na architekturze PowerPC
Pytania?
Źródła
gcov
lcov
http://www.verifysoft.com/en_ctcpp.html
Różne rodzaje pokrycia z przykładami
http://www.bullseye.com/
CTC++ TestCoverage
http://code.google.com/p/trucov/
BullseyeCoverage
http://ltp.sourceforge.net/coverage/lcov.php
Trucov
man gcov
http://gcc.gnu.org/onlinedocs/gcc/Gcov.html
http://www.javaranch.com/journal/2004/01/IntroToCodeCoverage.html
http://www.bullseye.com/coverage.html
Gcov on an embedded system (H.Blasum, F.Görgen, J.Urban)
http://sysrun.haifa.il.ibm.com/hrl/greps2007/papers/gcov-on-an-embedded-system.pdf