100% pokrycia testami nie jest łatwe

100% pokrycia testami nie jest łatwe
Pokrycie kodu testami to metryka, która od lat budzi emocje.

Jedni traktują ją jako niezbędny element pracy z jakością, inni jako statystykę o ograniczonej wartości. W wielu dyskusjach wciąż powtarza się przekonanie, że „pełne pokrycie jest proste do osiągnięcia, więc nie należy przywiązywać do tego wagi”. To jednak uproszczenie, które powstało w wyniku zniekształcenia pierwotnej idei – klasyczny przykład tego, co Martin Fowler określa mianem semantic diffusion. Fragment z jego tekstu o testach bez asercji, wielokrotnie powtarzany, zaczął funkcjonować jak miejska legenda branży programistycznej: nośna, ale w praktyce mało precyzyjna. 

Analiza przykładu przedstawionego przez Marka Seemana pokazuje, że mit o „łatwym 100% coverage” nie ma wiele wspólnego z rzeczywistością. Droga do pełnego pokrycia kodu w realnych systemach bywa wyboista, a nierzadko okazuje się po prostu nieopłacalna lub niewarta wysiłku.

Co daje wskaźnik pokrycia?

Pokrycie kodu pokazuje, które fragmenty programu zostały wykonane podczas testów. Brzmi to przydatnie, ale sama informacja o wykonaniu linii nie mówi nic o skuteczności testów. Test może uruchamiać kod bez jakiejkolwiek weryfikacji, a mimo to podbijać statystyki. Można też testować scenariusze nierealne lub kompletnie oderwane od tego, co dzieje się w środowisku produkcyjnym. Pokrycie nie powie nam, czy funkcja obsługuje wszystkie przypadki brzegowe, czy asercje są sensowne ani czy system poradzi sobie przy zewnętrznych zależnościach. 

Właśnie dlatego ta metryka pełni raczej funkcję kontrolną niż oceniającą. Wskazuje ona obszary, w których testów nie ma lub jest ich podejrzanie mało, ale sama w sobie nie ocenia ich jakości ani kompletności. 

Dlaczego 100% pokrycia wcale nie jest trywialne

W swoim artykule „100% coverage is not that trivial” Mark Seemann opisuje prostą metodę odczytującą rezerwację z SQL-owej bazy danych. 

100-procent-pokrycia-testami-nie-jest-latwe-org.png100-procent-pokrycia-testami-nie-jest-latwe-org-2.png

Kod ma zaledwie dwa rozgałęzienia logiczne, więc teoretycznie jego pełne pokrycie powinno być łatwe. W praktyce okazuje się inaczej.

Test napisany „na skróty”, pozbawiony asercji w bloku try/catch, pokrywa jedynie pierwszą linię, czyli utworzenie obiektu połączenia. Narzędzie Coverlet raportuje w tym przypadku zaledwie 18% pokrycia. Reszta metody pozostaje nieosiągalna, ponieważ każde kolejne wywołanie wymaga czegoś, czego test nie jest w stanie zapewnić: realnego połączenia do bazy danych, poprawnego schematu tabel oraz danych pozwalających przetestować oba warianty – kiedy rekord istnieje i kiedy nie istnieje. 

To pokazuje rzecz fundamentalną: w systemach zależnych od środowiska nie da się dojść do 100% pokrycia tanim kosztem. Aby rzeczywiście wykonać wszystkie ścieżki, potrzebne są pełne testy integracyjne, przygotowanie danych i zadbanie o stabilne środowisko testowe.

Jak podejść do pokrycia kodu

Najbardziej praktyczne użycie pokrycia polega na traktowaniu go jako wskazówki, a nie celu. Niski wynik w module o dużym znaczeniu zwykle sygnalizuje obszar wymagający uwagi. Z kolei wysoki procent nie oznacza automatycznie, że testy są dobre, może po prostu znaczyć, że kod został wykonany, ale niekoniecznie przetestowany.  

W praktyce duże znaczenie ma także to, jakim typem testów uzyskujemy pokrycie. Testy jednostkowe pozwalają zweryfikować logikę, ale to testy integracyjne odsłaniają problemy związane z komunikacją między komponentami, konfiguracją systemu czy działaniem zewnętrznych zależności. Testy mutacyjne z kolei pozwalają sprawdzić, czy asercje faktycznie mają siłę detekcji błędów.

Wszystko to sprowadza się do jednego: zakres testowania powinien wynikać z ryzyka i potrzeb projektu, a nie z arbitralnego procentu ustawionego jako cel.

Podsumowanie

Pokrycie kodu testami nie jest ani wyrocznią jakości, ani zbędną statystyką. To użyteczny wskaźnik pomocniczy, o ile nie traktujemy go jako celu samego w sobie. Przykład Seemanna pokazuje, że osiągnięcie 100% pokrycia w realnych systemach wymaga integracji, danych testowych i środowiska, a więc zdecydowanie więcej niż napisanie kilku uproszczonych testów. 

Najrozsądniejsze podejście to wykorzystywanie pokrycia jako narzędzia do identyfikacji obszarów ryzyka i wspierania decyzji o tym, gdzie testować, a nie ile testów napisać. 
 

Co najczęściej powoduje błędne interpretacje pokrycia testami?
Co najczęściej powoduje błędne interpretacje pokrycia testami?
33.33 %
Traktowanie go jako miary jakości.
50 %
Oderwanie metryki od kontekstu biznesowego.
0 %
Brak rozróżnienia typów testów.
16.67 %
Presja raportowa i KPI.
Łącznie głosów: 6

To powinno Cię zainteresować