Code coverage w .NET — jak mierzyć i dlaczego 100% to zły cel
Code coverage mierzy, który procent linii (albo gałęzi) kodu został wykonany podczas uruchomienia testów. To użyteczny sygnał, gdzie testów brakuje — ale wysoki procent nie oznacza automatycznie, że kod jest dobrze przetestowany.
Uruchomienie pomiaru — coverlet.collector
dotnet add package coverlet.collector
dotnet test --collect:"XPlat Code Coverage"Po uruchomieniu coverlet.collector generuje plik coverage.cobertura.xml w katalogu TestResults/{guid}/ — surowe dane o tym, które linie zostały wykonane. Sam XML jest nieczytelny dla człowieka, więc kolejny krok to zamiana go na raport HTML.
Czytelny raport HTML — ReportGenerator
dotnet tool install -g dotnet-reportgenerator-globaltool
reportgenerator -reports:"TestResults/**/coverage.cobertura.xml" -targetdir:"CoverageReport" -reporttypes:HtmlOtwarcie CoverageReport/index.html pokazuje pokrycie per projekt, per klasa, per metoda — z podświetleniem konkretnych linii, które nie zostały wykonane przez żaden test.
Line coverage vs branch coverage — różnica, która ma znaczenie
public string OcenKlienta(int liczbaZamowien)
{
if (liczbaZamowien > 100)
return "VIP";
return "Standard";
}[Fact]
public void OcenKlienta_DuzoZamowien_ZwracaVip()
{
Assert.Equal("VIP", Serwis.OcenKlienta(150));
}Ten jeden test daje 100% line coverage dla metody OcenKlienta — każda linia kodu została wykonana (obie instrukcje return znajdują się na osobnych liniach, ale narzędzie liczy wykonane linie, nie ścieżki). Mimo to branch coverage wynosi 50% — gałąź else (liczbaZamowien <= 100) nigdy nie została przetestowana. Gdyby ktoś zamienił > na >=, ten jeden test by tego nie wykrył.
[Fact]
public void OcenKlienta_MaloZamowien_ZwracaStandard()
{
Assert.Equal("Standard", Serwis.OcenKlienta(50));
}Dopiero dodanie drugiego testu (sprawdzającego gałąź przeciwną) daje realne 100% branch coverage. Line coverage bez branch coverage potrafi dać fałszywe poczucie bezpieczeństwa — warto włączyć pomiar branch coverage (reportgenerator pokazuje oba), nie tylko line coverage.
Dlaczego 100% coverage nie gwarantuje braku bugów
[Fact]
public void ObliczRabat_DzialaPoprawnie()
{
var wynik = Serwis.ObliczRabat(5);
// brak asercji — test "przechodzi", bo nic nie sprawdza!
}Ten test wykonuje każdą linię metody ObliczRabat — coverage pokaże 100%. Test nie sprawdza jednak absolutnie niczego: brak Assert oznacza, że test przejdzie niezależnie od tego, co metoda zwróci. Wysoki coverage mówi tylko “ten kod został wykonany”, nie mówi “ten kod działa poprawnie” — to dwie różne rzeczy, które łatwo pomylić, patrząc tylko na procent w raporcie.
Praktyczny próg — gdzie faktycznie warto celować w wysoki coverage
Nie ma jednej magicznej liczby (80%? 90%?), która pasuje do każdego projektu. Sensowniejsze pytanie: które części kodu najbardziej boli, gdy się zepsują? Logika biznesowa w warstwie Domain/Application (zobacz Clean Architecture) zasługuje na wysoki coverage z realnymi asercjami. Proste DTO, automatycznie generowane gettery/settery czy kod konfiguracyjny startowego Program.cs — dużo mniej. Pogoń za 100% coverage w całym projekcie często kończy się testami, które istnieją tylko po to, żeby podnieść liczbę w raporcie, nie po to, żeby faktycznie coś zweryfikować.
Podsumowanie
Code coverage mierzysz przez dotnet test --collect:"XPlat Code Coverage" i zamieniasz na czytelny raport HTML przez reportgenerator. Kluczowa różnica: line coverage pokazuje, które linie zostały wykonane, branch coverage pokazuje, które ścieżki logiczne (if/else) zostały przetestowane — ten drugi wskaźnik wyłapuje więcej realnych luk. Wysoki procent coverage bez sensownych asercji w testach nic nie gwarantuje — traktuj coverage jako mapę pokazującą, gdzie testów brakuje, nie jako cel sam w sobie.
🚀 Co dalej?
Zobacz to w praktyce na wideo i pobierz darmową roadmapę, żeby ułożyć naukę w spójną ścieżkę do pierwszej pracy.
- 🗺️ Pobierz darmową roadmapę Junior .NET Developer — 12 kroków od podstaw C# do pierwszej pracy: dev-hobby.pl
- 🎬 Subskrybuj kanał YouTube — nowe filmy co tydzień.
Zamień wiedzę w umiejętności
Pobierz darmową Roadmapę .NET i ułóż takie tematy jak ten w spójną ścieżkę do pierwszej pracy.
Pobieram roadmapę →