Używanie pokrycia kodu do testowania jednostkowego
Ważne
W tym artykule wyjaśniono tworzenie przykładowego projektu. Jeśli masz już projekt, możesz przejść do sekcji Narzędzia pokrycia kodu.
Testy jednostkowe pomagają zapewnić funkcjonalność i zapewnić weryfikację na potrzeby refaktoryzacji. Pokrycie kodu to miara ilości kodu uruchamianego przez testy jednostkowe — wiersze, gałęzie lub metody. Jeśli na przykład masz prostą aplikację z tylko dwoma gałęziami warunkowymi kodu (gałąź a i gałąź b), test jednostkowy weryfikujący gałąź warunkową, będzie zgłaszać pokrycie kodu gałęzi o wartości 50%.
W tym artykule omówiono użycie pokrycia kodu na potrzeby testowania jednostkowego za pomocą rozwiązania Coverlet i generowania raportów przy użyciu narzędzia ReportGenerator. Chociaż ten artykuł koncentruje się na języku C# i xUnit jako strukturze testowej, narzędzia MSTest i NUnit również będą działać. Coverlet to projekt open source w witrynie GitHub , który udostępnia międzyplatformową strukturę pokrycia kodu dla języka C#. Coverlet jest częścią platformy .NET Foundation. Coverlet zbiera dane przebiegu testu pokrycia Cobertura, które są używane do generowania raportów.
Ponadto w tym artykule szczegółowo opisano sposób używania informacji dotyczących pokrycia kodu zebranych z przebiegu testu Coverlet w celu wygenerowania raportu. Generowanie raportu jest możliwe przy użyciu innego projektu open source w witrynie GitHub — ReportGenerator. ReportGenerator konwertuje raporty pokrycia generowane przez Cobertura między innymi na raporty czytelne dla człowieka w różnych formatach.
Ten artykuł jest oparty na przykładowym projekcie kodu źródłowego dostępnym w przeglądarce przykładów.
System testowy
"Test systemu" odnosi się do kodu, względem którego piszesz testy jednostkowe, może to być obiekt, usługa lub cokolwiek innego, co uwidacznia funkcje testowalne. W tym artykule utworzysz bibliotekę klas, która będzie systemem testowym i dwoma odpowiednimi projektami testów jednostkowych.
Tworzenie biblioteki klas
W wierszu polecenia w nowym katalogu o nazwie UnitTestingCodeCoverage
utwórz nową bibliotekę klas platformy .NET standard przy dotnet new classlib
użyciu polecenia :
dotnet new classlib -n Numbers
Poniższy fragment kodu definiuje prostą PrimeService
klasę, która udostępnia funkcje umożliwiające sprawdzenie, czy liczba jest liczbą główną. Skopiuj poniższy fragment kodu i zastąp zawartość pliku Class1.cs , który został automatycznie utworzony w katalogu Numbers . Zmień nazwę pliku Class1.cs na PrimeService.cs.
namespace System.Numbers
{
public class PrimeService
{
public bool IsPrime(int candidate)
{
if (candidate < 2)
{
return false;
}
for (int divisor = 2; divisor <= Math.Sqrt(candidate); ++divisor)
{
if (candidate % divisor == 0)
{
return false;
}
}
return true;
}
}
}
Napiwek
Warto wspomnieć, że Numbers
biblioteka klas została celowo dodana do System
przestrzeni nazw. System.Math Umożliwia to dostęp bez using System;
deklaracji przestrzeni nazw. Aby uzyskać więcej informacji, zobacz Przestrzeń nazw (odwołanie w C#).
Tworzenie projektów testowych
Utwórz dwa nowe szablony projektu testowego xUnit (.NET Core) z tego samego wiersza polecenia przy użyciu dotnet new xunit
polecenia :
dotnet new xunit -n XUnit.Coverlet.Collector
dotnet new xunit -n XUnit.Coverlet.MSBuild
Oba nowo utworzone projekty testowe xUnit muszą dodać odwołanie do projektu biblioteki klas Numbers . Dzięki temu projekty testowe mają dostęp do usługi PrimeService na potrzeby testowania. W wierszu polecenia użyj dotnet add
polecenia :
dotnet add XUnit.Coverlet.Collector\XUnit.Coverlet.Collector.csproj reference Numbers\Numbers.csproj
dotnet add XUnit.Coverlet.MSBuild\XUnit.Coverlet.MSBuild.csproj reference Numbers\Numbers.csproj
Projekt MSBuild jest odpowiednio nazwany, ponieważ będzie zależeć od pakietu NuGet coverlet.msbuild . Dodaj tę zależność pakietu, uruchamiając dotnet add package
polecenie :
cd XUnit.Coverlet.MSBuild && dotnet add package coverlet.msbuild && cd ..
Poprzednie polecenie skutecznie zmieniało zakres katalogów w projekcie testowym MSBuild , a następnie dodano pakiet NuGet. Po wykonaniu tej czynności zmieniono katalogi, co spowoduje przejście na wyższy poziom.
Otwórz oba pliki UnitTest1.cs i zastąp ich zawartość poniższym fragmentem kodu. Zmień nazwę plików UnitTest1.cs na PrimeServiceTests.cs.
using System.Numbers;
using Xunit;
namespace XUnit.Coverlet
{
public class PrimeServiceTests
{
readonly PrimeService _primeService;
public PrimeServiceTests() => _primeService = new PrimeService();
[Theory]
[InlineData(-1), InlineData(0), InlineData(1)]
public void IsPrime_ValuesLessThan2_ReturnFalse(int value) =>
Assert.False(_primeService.IsPrime(value), $"{value} should not be prime");
[Theory]
[InlineData(2), InlineData(3), InlineData(5), InlineData(7)]
public void IsPrime_PrimesLessThan10_ReturnTrue(int value) =>
Assert.True(_primeService.IsPrime(value), $"{value} should be prime");
[Theory]
[InlineData(4), InlineData(6), InlineData(8), InlineData(9)]
public void IsPrime_NonPrimesLessThan10_ReturnFalse(int value) =>
Assert.False(_primeService.IsPrime(value), $"{value} should not be prime");
}
}
Tworzenie rozwiązania
W wierszu polecenia utwórz nowe rozwiązanie, aby hermetyzować bibliotekę klas i dwa projekty testowe. dotnet sln
Za pomocą polecenia :
dotnet new sln -n XUnit.Coverage
Spowoduje to utworzenie nowej nazwy XUnit.Coverage
pliku rozwiązania w katalogu UnitTestingCodeCoverage . Dodaj projekty do katalogu głównego rozwiązania.
Skompiluj dotnet build
rozwiązanie przy użyciu polecenia :
dotnet build
Jeśli kompilacja zakończy się pomyślnie, utworzono trzy projekty, odpowiednio przywoływały projekty i pakiety oraz poprawnie zaktualizowano kod źródłowy. Gotowe!
Narzędzia pokrycia kodu
Istnieją dwa typy narzędzi pokrycia kodu:
- DataCollectors: Funkcja DataCollectors monitoruje wykonywanie testów i zbiera informacje o przebiegach testów. Raportują zebrane informacje w różnych formatach wyjściowych, takich jak XML i JSON. Aby uzyskać więcej informacji, zobacz swój pierwszy element DataCollector.
- Generatory raportów: użyj danych zebranych z przebiegów testów, aby wygenerować raporty, często w stylu HTML.
W tej sekcji skupimy się na narzędziach modułu zbierającego dane.
Platforma .NET zawiera wbudowany moduł zbierający dane pokrycia kodu, który jest również dostępny w programie Visual Studio. Ten moduł zbierający dane generuje binarny plik pokrycia , który może służyć do generowania raportów w programie Visual Studio. Plik binarny nie jest czytelny dla człowieka i musi zostać przekonwertowany na format czytelny dla człowieka, zanim będzie można go użyć do generowania raportów poza programem Visual Studio.
Napiwek
Narzędzie dotnet-coverage
to międzyplatformowe narzędzie, które może służyć do konwertowania pliku wyników testu pokrycia binarnego na format czytelny dla człowieka. Aby uzyskać więcej informacji, zobacz dotnet-coverage.
Coverlet to alternatywa typu open source dla wbudowanego modułu zbierającego. Generuje wyniki testów jako czytelne dla człowieka pliki XML Cobertura, które następnie mogą służyć do generowania raportów HTML. Aby użyć rozwiązania Coverlet do pokrycia kodu, istniejący projekt testu jednostkowego musi mieć odpowiednie zależności pakietu lub alternatywnie polegać na narzędziach globalnych platformy .NET i odpowiednim pakiecie NuGet coverlet.console .
Integracja z testem platformy .NET
Szablon projektu testowego xUnit jest już domyślnie integrowany z elementem coverlet.collector .
W wierszu polecenia zmień katalogi na projekt XUnit.Coverlet.Collector i uruchom dotnet test
polecenie:
cd XUnit.Coverlet.Collector && dotnet test --collect:"XPlat Code Coverage"
Uwaga
Argument "XPlat Code Coverage"
jest przyjazną nazwą odpowiadającą modułom zbierającym dane z coverletu. Ta nazwa jest wymagana, ale nie uwzględnia wielkości liter. Aby użyć polecenia . Wbudowany moduł zbierający dane pokrycia kodu platformy NET użyj polecenia "Code Coverage"
.
W ramach przebiegu wynikowy plik coverage.cobertura.xml jest zwracany do katalogu TestResults.dotnet test
Plik XML zawiera wyniki. Jest to opcja międzyplatformowa, która opiera się na interfejsie wiersza polecenia platformy .NET i doskonale sprawdza się w przypadku systemów kompilacji, w których program MSBuild nie jest dostępny.
Poniżej znajduje się przykładowy plik coverage.cobertura.xml .
<?xml version="1.0" encoding="utf-8"?>
<coverage line-rate="1" branch-rate="1" version="1.9" timestamp="1592248008"
lines-covered="12" lines-valid="12" branches-covered="6" branches-valid="6">
<sources>
<source>C:\</source>
</sources>
<packages>
<package name="Numbers" line-rate="1" branch-rate="1" complexity="6">
<classes>
<class name="Numbers.PrimeService" line-rate="1" branch-rate="1" complexity="6"
filename="Numbers\PrimeService.cs">
<methods>
<method name="IsPrime" signature="(System.Int32)" line-rate="1"
branch-rate="1" complexity="6">
<lines>
<line number="8" hits="11" branch="False" />
<line number="9" hits="11" branch="True" condition-coverage="100% (2/2)">
<conditions>
<condition number="7" type="jump" coverage="100%" />
</conditions>
</line>
<line number="10" hits="3" branch="False" />
<line number="11" hits="3" branch="False" />
<line number="14" hits="22" branch="True" condition-coverage="100% (2/2)">
<conditions>
<condition number="57" type="jump" coverage="100%" />
</conditions>
</line>
<line number="15" hits="7" branch="False" />
<line number="16" hits="7" branch="True" condition-coverage="100% (2/2)">
<conditions>
<condition number="27" type="jump" coverage="100%" />
</conditions>
</line>
<line number="17" hits="4" branch="False" />
<line number="18" hits="4" branch="False" />
<line number="20" hits="3" branch="False" />
<line number="21" hits="4" branch="False" />
<line number="23" hits="11" branch="False" />
</lines>
</method>
</methods>
<lines>
<line number="8" hits="11" branch="False" />
<line number="9" hits="11" branch="True" condition-coverage="100% (2/2)">
<conditions>
<condition number="7" type="jump" coverage="100%" />
</conditions>
</line>
<line number="10" hits="3" branch="False" />
<line number="11" hits="3" branch="False" />
<line number="14" hits="22" branch="True" condition-coverage="100% (2/2)">
<conditions>
<condition number="57" type="jump" coverage="100%" />
</conditions>
</line>
<line number="15" hits="7" branch="False" />
<line number="16" hits="7" branch="True" condition-coverage="100% (2/2)">
<conditions>
<condition number="27" type="jump" coverage="100%" />
</conditions>
</line>
<line number="17" hits="4" branch="False" />
<line number="18" hits="4" branch="False" />
<line number="20" hits="3" branch="False" />
<line number="21" hits="4" branch="False" />
<line number="23" hits="11" branch="False" />
</lines>
</class>
</classes>
</package>
</packages>
</coverage>
Napiwek
Alternatywnie możesz użyć pakietu MSBuild, jeśli system kompilacji korzysta już z programu MSBuild. W wierszu polecenia zmień katalogi na projekt XUnit.Coverlet.MSBuild i uruchom dotnet test
polecenie:
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura
Wynikowy plik coverage.cobertura.xml jest wyjściowy. Przewodnik integracji programu MSBuild można znaleźć tutaj
Generowanie raportów
Teraz, gdy możesz zbierać dane z przebiegów testów jednostkowych, możesz wygenerować raporty przy użyciu narzędzia ReportGenerator. Aby zainstalować pakiet NuGet ReportGenerator jako narzędzie globalne platformy .NET, użyj dotnet tool install
polecenia :
dotnet tool install -g dotnet-reportgenerator-globaltool
Uruchom narzędzie i podaj odpowiednie opcje, biorąc pod uwagę dane wyjściowe coverage.cobertura.xml pliku z poprzedniego przebiegu testu.
reportgenerator
-reports:"Path\To\TestProject\TestResults\{guid}\coverage.cobertura.xml"
-targetdir:"coveragereport"
-reporttypes:Html
Po uruchomieniu tego polecenia plik HTML reprezentuje wygenerowany raport.
Zobacz też
- Pokrycie kodu testów jednostkowych programu Visual Studio
- GitHub — repozytorium Coverlet
- GitHub — repozytorium ReportGenerator
- Witryna projektu ReportGenerator
- Azure: Publikowanie wyników pokrycia kodu
- Azure: Przeglądanie wyników pokrycia kodu
- Polecenie testowe interfejsu wiersza polecenia platformy .NET
- dotnet-coverage
- Przykładowy kod źródłowy