2010-08-24 13 views
36

Używam gcov do pomiaru zasięgu w moim C++. Chciałbym uzyskać 100% pokrycia, ale przeszkadza mi to, że istnieje kilka linii kodu, które teoretycznie są nie do rozszyfrowania (metody, które są wymagane do wdrożenia, ale które nigdy nie są wywoływane, domyślne gałęzie oświadczeń switch, itp.). Każda z tych gałęzi zawiera instrukcję assert(false);, ale gcov nadal oznacza je jako nie trafione.Jak powiedzieć gcov, aby zignorować linie kodu C++, których nie da się zdefiniować?

Chciałbym móc powiedzieć gcov, aby zignorował te gałęzie. Czy istnieje sposób na przekazanie informacji o gcov - poprzez przypisanie kodu źródłowego lub innego mechanizmu?

+0

Co sprawia, że ​​jesteś tak pewny, że linie są unhittable? Jeśli tak jest, ponieważ nie udało Ci się ich trafić, to właśnie próbujesz się dowiedzieć z pokryciem kodu. – doron

+2

@ deus-ex-machina399: Nie, to nie dlatego, że nie mogłem ich uderzyć. Jest to spowodowane zrozumieniem i analizą kodu. Oczywiście mogę się mylić, ale nie używam analizy zasięgu kodu, aby zweryfikować moje zrozumienie kodu źródłowego. Używam analizy zasięgu kodu do sprawdzenia jakości mojego zestawu testów. – jchl

+1

@doron, przykładem kodu, który powinien być nieodporny, są ścieżki błędów w infrastrukturze testowej. Oczywiście, prawdopodobnie możesz obyć się bez takich ścieżek, ale ja je mam. –

Odpowiedz

35

Proszę użyć lcov.Ukrywa złożoność gcov za produkuje ładne wyjście umożliwia szczegółowe wyjście za test pozwala na łatwe filtrowanie plików i - TA-TAA - markery linii dla już ocenionych linii:

Od geninfo (1):

Poniższy znaczniki są rozpoznawane przez geninfo:

  • LCOV_EXCL_LINE
    • linie zawierające ten znacznik zostanie wyłączone.
  • LCOV_EXCL_START
    • wyznacza początek wykluczonego sekcji. Bieżąca linia jest częścią tej sekcji.
  • LCOV_EXCL_STOP
    • Zaznacza końcówkę wyłączone sekcji. Bieżąca linia nie jest częścią tej sekcji.
+0

Interesujące, nie słyszałem o LCOV. Dzięki za rekomendację! – jchl

+0

W końcu udało mi się przetestować to ... i po uaktualnieniu do wersji lcov> = 1.8, działa to uroku. Dzięki! – jchl

+14

Nie jestem fanem odpowiedzi w formularzu "użyj innego narzędzia". Naprawdę chcę wiedzieć, jak uzyskać gcov, aby zignorować linie i nie ma opcji przełączania na lcov. To nie odpowiada na pytanie. –

0

Nie wierzę, że to możliwe. Gcov zależy od gcc, aby wygenerować dodatkowy kod w celu wygenerowania pokrycia. Sam GCov po prostu analizuje dane. Oznacza to, że Gcov nie może zanalizować kodu lepiej niż gcc (i zakładam, że używasz -Wall i usunięto kod zgłoszony jako nieosiągalny).

Należy pamiętać, że funkcje relokowalne można wywoływać z dowolnego miejsca, potencjalnie nawet z zewnętrznych bibliotek dll lub plików wykonywalnych, więc nie ma możliwości, aby kompilator wiedział, które funkcje relokowalne nie będą wywoływane, ani jakie wejście mogą mieć te funkcje.

Prawdopodobnie będziesz potrzebował użyć narzędzia do analizy statycznej, aby uzyskać potrzebne informacje.

1

Czy mógłbyś wprowadzić testy jednostkowe odpowiednich funkcji, które istnieją tylko po to, aby wyłączyć Gcov up przez bezpośrednie atakowanie teoretycznie nieodpornych ścieżek kodu? Ponieważ są to testy jednostkowe, mogą one zignorować "niemożliwość" sytuacji. Mogą wywoływać funkcje, które nigdy nie są wywoływane, przekazywać niepoprawne wartości wyliczeniowe, aby przechwytywać domyślne gałęzie itp.

Następnie należy uruchomić te testy tylko w wersji kodu skompilowanej z NDEBUG, lub uruchomić je w uprzęży, która testuje że aktywacja jest uruchamiana - niezależnie od tego, co obsługuje twoja struktura testowa.

To trochę dziwne, ponieważ specyfikacja mówi, że kod musi tam być, a nie specyfikacja zawierająca wymagania funkcjonalne w kodzie. W szczególności oznacza to, że twoje testy nie testują tych wymagań, co jest równie dobrym powodem, aby utrzymać wymagania w działaniu. Osobiście chciałbym zmodyfikować specyfikację, aby powiedzieć: "jeśli wywołana z nieprawidłową wartością wyliczenia, funkcja nie powiedzie się assert. Dzwoniący nie będą wywoływać funkcji z nieprawidłową wartością wyliczenia w trybie zwolnienia". Lub niektóre takie.

Przypuszczalnie to, co obecnie mówi, jest na wzór "wszystkie instrukcje przełączników muszą mieć domyślny przypadek". Oznacza to jednak, że standardy kodowania zakłócają obserwowalne zachowanie (przynajmniej możliwe do zaobserwowania pod gcov) poprzez wprowadzenie martwego kodu. Standardy kodowania nie powinny tego robić, więc specyfikacja funkcjonalna powinna w miarę możliwości uwzględniać standardy kodowania.

W przeciwnym razie możesz owinąć niemożliwy do zmienienia kod w #if !GCOV_BUILD i zrobić osobną kompilację dla korzyści gcov. Ta kompilacja nie spełni pewnych wymagań, ale pod warunkiem, że twoja analiza poprawności kodu jest poprawna, daje ci pewność, że pakiet testowy testuje wszystko inne.

Edycja: mówisz, że używasz generatora podejrzanych kodów, ale prosisz też o rozwiązanie, opisując kod źródłowy. Jeśli zmieniasz źródło, czy możesz po prostu usunąć martwy kod w wielu przypadkach? Nie oznacza to, że zmiana generowanego źródła jest idealna, ale potrzeby muszą ...

+0

To nie jest tak, że "specyfikacja" mówi, że funkcje muszą tam być. Mamy generator kodu, który generuje prototypy funkcji, nawet jeśli nie są używane. (Naprawa generatora kodu byłaby lepszą opcją, ale niestety to nie jest pod moją kontrolą.) Inną sytuacją, w której czasami się pojawia, jest miejsce, w którym implementujesz interfejs (tj. Wywodzi się z klasy z czystymi funkcjami wirtualnymi), ale używasz tylko część tego interfejsu. – jchl

+0

Po bezpośrednim wywołaniu funkcji testowanie funkcji nie jest złym pomysłem, chociaż uruchomienie testów na kompilacji NDEBUG byłoby bolesne (obecnie nasza jednostka testuje wszystkie uruchamiane kompilacje debugowania). To brzmi jak więcej pracy niż jest warte. Mogłem po prostu pozbyć się zapewnień, chociaż lubię je tam w celach dokumentacyjnych. Mógłbym je zastąpić specjalnym wyjątkiem, który nigdy nie zostanie złapany, chyba że podczas testu jednostkowego .... to nie jest zły pomysł. – jchl

+0

@jchl: "implementujesz interfejs (czyli wywodzi się z klasy o czystych funkcjach wirtualnych), ale używasz tylko części tego interfejsu." - rodzaj. Jeśli jednak piszę kompleksowe testy dla klasy, nadal będę miał klasę określającą, co robią i wywołują nieużywane funkcje z testów, aby upewnić się, że to robią. A jeśli nie piszę kompleksowych testów, nie obchodzi mnie, czy mam zasięg kodu, czy nie ;-) –

Powiązane problemy