Poprzednio pokazałem pokrótce, jak testować pokrycie kodu narzedziem gcov…idąc za ciosem, dziś pokażę na przykładzie, jak wykorzystać gcov do sprawdzenia pokrycia kodu testami jednostkowymi.
Przykład
Pokrycie kodu testami sprawdzimy na przykładzie prostej klasy Calculator. Ma ona tylko dwie funkcje – dodawanie i dzielenie:
// calculator.h class Calculator { public: static double add(double a, double b) { return a + b; } static double div(double a, double b) { if (0 == b) throw "Zero division exception!"; return a / b; } };
Jak widzisz, funkcja add po prostu zwraca sumę liczb, a funkcja div dodatkowo rzuca wyjątek w przypadku dzielenia przez zero (dla uproszczenia – zwykły ciąg znaków).
Zobaczmy teraz na zestaw testów jednostkowych dla naszego kalkulatora. Zeby nie komplikowac – dany test po prostu wypisuje odpowiedni komunikat w razie niepowodzenia:
// program.cpp #include <iostream> using namespace std; void testAdd() { if (Calculator::add(3, 7) != 10) cout << "add function returned bad result. Line: " << __LINE__; if (Calculator::add(-1.5, -8.5) != -10) cout << "add function returned bad result. Line: " << __LINE__; } void testDiv() { if (Calculator::div(10, 5) != 2) cout << "div function returned bad result. Line: " << __LINE__; if (Calculator::div(4.5, 9) != 0.5) cout << "div function returned bad result. Line: " << __LINE__; } int main() { testAdd(); testDiv(); return 0; }
Mamy tylko dwa testy: testAdd i testDiv, które sprawdzają wynik działania funkcji add oraz div.
Zróbmy teraz test pokrycia kodu narzędziem gcov:
> g++ -fprofile-arcs -ftest-coverage -o program program.cpp > ./program > gcov program.cpp
W wyniku tego na okno terminala dostajemy:
... File 'calculator.h' Lines executed:83.33% of 6 ...
Widzimy, że pokrycie kodu przez testy dla modułu calculator.h wynosi 83.33%. Liczba ta to po prostu procent kodu, jaki został wykonany w wyniku działania testów.
Spróbujmy poprawić nasz wynik. Zaglądamy do wygenerowanego raportu pokrycia program.cpp.gcov i oto, co widzimy:
-: 1:class Calculator -: 2:{ -: 3:public: 2: 4: static double add(double a, double b) -: 5: { 2: 6: return a + b; -: 7: } -: 8: 2: 9: static double div(double a, double b) -: 10: { 2: 11: if (b == 0) #####: 12: throw "Zero division exception!"; -: 13: 2: 14: return a / b; -: 15: } -: 16:};
Okazuje się, że funkcja div kalkulatora ma zaimplementowaną obsługę dzielenia przez zero, a my jej nie testujemy. Dodajmy więc test na dzielenie przez zero:
void testDiv() { if (Calculator::div(10, 5) != 2) cout << "div function returned bad result. Line: " << __LINE__; if (Calculator::div(4.5, 9) != 0.5) cout << "div function returned bad result. Line: " << __LINE__; try { Calculator::div(10, 0); } catch (const char* ) { return; // wyjatek został rzucony, wiec konczymy test pozytywnie } cout << "div function is not handling zero division. Line: " << __LINE__ ; }
Teraz, jeśli funkcja div w przypadku dzielenia przez zero nie rzuci wyjątku – zostaniemy o tym poinformowani.
Wszystko jest już jak należy – możemy więc ponownie zbadać pokrycie kodu:
> g++ -fprofile-arcs -ftest-coverage -o program program.cpp > ./program > gcov program.cpp
Tym razem na okno terminala dostajemy:
... File 'calculator.h' Lines executed:100.00% of 6 ...
Czyli udało nam się doprowadzić do perfekcji pokrycie naszego kodu testami :)
Podsumowanie
Narzędzie gcov pozwoliło nam zmierzyć stopień pokrycia kodu testami jednostkowymi. Dzięki niemu szybko zlokalizowaliśmy i załataliśmy lukę w testach.
April 16th, 2011 on 22:01
Bardzo przystępny i zrozumiały opis, jestem na tak :)
October 2nd, 2011 on 06:28
Ha – znakomity opis! Wiedziałem że są takie narzędzia w GCC tylko nie wiedziałem od której strony sie za nie zabrać. Wczoraj przetestowałem sobie profilowanie, teraz pokrycie. I niech mi ktoś jeszcze powie że GCC jest “be” bo opensource bo darmowe itp. to oberwie ;)