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 UnitTestingCodeCoverageutwó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.

dotnet sln XUnit.Coverage.sln add **/*.csproj --in-root

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.

Unit test-generated report

Zobacz też

Następne kroki