Použití pokrytí kódu pro testování jednotek
Důležité
Tento článek vysvětluje vytvoření ukázkového projektu. Pokud už projekt máte, můžete přeskočit k části Nástroje pokrytí kódu.
Testy jednotek pomáhají zajistit funkčnost a poskytnout způsob ověření pro refaktoring. Pokrytí kódu je měření množství kódu, které se spouští testy jednotek – buď řádky, větve nebo metody. Pokud máte například jednoduchou aplikaci s pouze dvěma podmíněnými větvemi kódu (větev a a větev b), test jednotek, který ověřuje podmíněnou větev a bude hlásit pokrytí kódu větve o 50 %.
Tento článek popisuje použití pokrytí kódu pro testování jednotek pomocí Coverletu a generování sestav pomocí ReportGeneratoru. I když se tento článek zaměřuje na C# a xUnit jako testovací architekturu, msTest i NUnit by také fungovaly. Coverlet je opensourcový projekt na GitHubu , který poskytuje architekturu pokrytí kódu pro různé platformy pro jazyk C#. Coverlet je součástí .NET Foundation. Coverlet shromažďuje data testovacích běhů pokrytí Cobertura, která se používají pro generování sestav.
Kromě toho tento článek podrobně popisuje použití informací o pokrytí kódu shromážděných z testovacího spuštění Coverletu ke generování sestavy. Generování sestav je možné pomocí jiného opensourcového projektu na GitHubu – ReportGenerator. ReportGenerator převádí sestavy pokrytí generované Cobertura mimo jiné na sestavy čitelné člověkem v různých formátech.
Tento článek je založený na projektu ukázkového zdrojového kódu, který je k dispozici v prohlížeči ukázek.
Systém pod testem
"Systém pod testem" odkazuje na kód, proti kterému píšete testy jednotek, může se jednat o objekt, službu nebo cokoli jiného, co zpřístupňuje testovatelné funkce. V tomto článku vytvoříte knihovnu tříd, která bude systémem pod testem, a dva odpovídající projekty testů jednotek.
Vytvoření knihovny tříd
Z příkazového řádku v novém adresáři s názvem UnitTestingCodeCoverage
vytvořte novou knihovnu dotnet new classlib
tříd .NET Standard pomocí příkazu:
dotnet new classlib -n Numbers
Následující fragment kódu definuje jednoduchou PrimeService
třídu, která poskytuje funkce pro kontrolu, jestli je číslo prime. Zkopírujte níže uvedený fragment kódu a nahraďte obsah souboru Class1.cs , který se automaticky vytvořil v adresáři Numbers . Přejmenujte soubor 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;
}
}
}
Tip
Stojí za zmínku Numbers
, že knihovna tříd byla záměrně přidána System
do oboru názvů. To umožňuje System.Math přístup bez using System;
deklarace oboru názvů. Další informace najdete v tématu obor názvů (referenční dokumentace jazyka C#).
Vytváření testovacích projektů
Pomocí příkazu vytvořte ze stejného příkazového řádku dotnet new xunit
dvě nové šablony testovacího projektu xUnit (.NET Core):
dotnet new xunit -n XUnit.Coverlet.Collector
dotnet new xunit -n XUnit.Coverlet.MSBuild
Oba nově vytvořené projekty testů xUnit musí přidat odkaz na projekt knihovny tříd Numbers . To znamená, že testovací projekty mají přístup k PrimeService pro testování. Z příkazového řádku použijte dotnet add
příkaz:
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 se pojmenuje odpovídajícím způsobem, protože bude záviset na balíčku coverlet.msbuild NuGet. Přidejte tuto závislost balíčku spuštěním dotnet add package
příkazu:
cd XUnit.Coverlet.MSBuild && dotnet add package coverlet.msbuild && cd ..
Předchozí příkaz efektivně změnil adresáře rozsahu na projekt testu MSBuild a pak přidal balíček NuGet. Až to bylo hotové, změnilo se adresáře a zkrotilo se o jednu úroveň výš.
Otevřete oba soubory UnitTest1.cs a nahraďte jejich obsah následujícím fragmentem kódu. Přejmenujte soubory 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");
}
}
Vytvoření řešení
Na příkazovém řádku vytvořte nové řešení pro zapouzdření knihovny tříd a dvou testovacích projektů. dotnet sln
Pomocí příkazu:
dotnet new sln -n XUnit.Coverage
Tím se v adresáři UnitTestingCodeCoverage vytvoří nový název XUnit.Coverage
souboru řešení. Přidejte projekty do kořenového adresáře řešení.
Sestavte řešení pomocí dotnet build
příkazu:
dotnet build
Pokud je sestavení úspěšné, vytvořili jste tři projekty, správně odkazované projekty a balíčky a aktualizovali zdrojový kód správně. Hotovo!
Nástroje pro pokrytí kódu
Existují dva typy nástrojů pro pokrytí kódu:
- DataCollectors: DataCollectors monitorují spouštění testů a shromažďují informace o testovacích spuštěních. Sestavují shromážděné informace v různých výstupních formátech, jako jsou XML a JSON. Další informace najdete v prvním dataCollectoru.
- Generátory sestav: Pomocí dat shromážděných z testovacích běhů můžete generovat sestavy, často jako ve stylu HTML.
V této části se zaměřujeme na nástroje kolektoru dat.
.NET obsahuje integrovaný kolektor dat pokrytí kódu, který je k dispozici také v sadě Visual Studio. Tento kolektor dat generuje binární soubor .coverage , který lze použít ke generování sestav v sadě Visual Studio. Binární soubor není čitelný pro člověka a musí být převeden do čitelného formátu, aby bylo možné generovat sestavy mimo Visual Studio.
Tip
Tento dotnet-coverage
nástroj je multiplatformní nástroj, který lze použít k převodu souboru výsledků binárního testu pokrytí do čitelného formátu člověka. Další informace najdete v tématu dotnet-coverage.
Coverlet je opensourcová alternativa k integrované kolekci. Generuje výsledky testů jako soubory CObertura XML čitelné člověkem, které lze pak použít ke generování sestav HTML. Pokud chcete použít Coverlet pro pokrytí kódu, musí mít existující projekt testování jednotek odpovídající závislosti balíčku nebo případně spoléhat na globální nástroje .NET a odpovídající balíček NuGet coverlet.console .
Integrace s testem .NET
Šablona projektu testu xUnit se už ve výchozím nastavení integruje s coverlet.collector .
Na příkazovém řádku změňte adresáře na projekt XUnit.Coverlet.Collector a spusťte dotnet test
příkaz:
cd XUnit.Coverlet.Collector && dotnet test --collect:"XPlat Code Coverage"
Poznámka:
Argument "XPlat Code Coverage"
je popisný název, který odpovídá kolektorům dat z Coverletu. Tento název je povinný, ale nerozlišuje velká a malá písmena. Chcete-li použít . Integrovaná kolekce dat Pokrytí kódu NET, použijte "Code Coverage"
.
V rámci dotnet test
spuštění je výsledný soubor coverage.cobertura.xml výstupem do adresáře TestResults . Soubor XML obsahuje výsledky. Jedná se o multiplatformní možnost, která spoléhá na rozhraní příkazového řádku .NET a je skvělá pro systémy sestavení, ve kterých není nástroj MSBuild k dispozici.
Níže je příklad souboru 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>
Tip
Jako alternativu můžete použít balíček MSBuild, pokud váš systém sestavení již využívá nástroj MSBuild. Na příkazovém řádku změňte adresáře na projekt XUnit.Coverlet.MSBuild a spusťte dotnet test
příkaz:
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura
Výsledný soubor coverage.cobertura.xml je výstup. Tady můžete postupovat podle průvodce integrací nástroje MSBuild.
Generování sestav
Teď, když máte možnost shromažďovat data z běhů testů jednotek, můžete pomocí ReportGeneratoru generovat sestavy. Pokud chcete balíček NuGet ReportGenerator nainstalovat jako globální nástroj .NET, použijte tento dotnet tool install
příkaz:
dotnet tool install -g dotnet-reportgenerator-globaltool
Spusťte nástroj a zadejte požadované možnosti s ohledem na výstupní coverage.cobertura.xml soubor z předchozího testovacího spuštění.
reportgenerator
-reports:"Path\To\TestProject\TestResults\{guid}\coverage.cobertura.xml"
-targetdir:"coveragereport"
-reporttypes:Html
Po spuštění tohoto příkazu představuje soubor HTML vygenerovanou sestavu.
Viz také
- Pokrytí kódu testu jednotek v sadě Visual Studio
- GitHub – úložiště Coverlet
- GitHub – úložiště ReportGenerator
- Web projektu ReportGenerator
- Azure: Publikování výsledků pokrytí kódu
- Azure: Kontrola výsledků pokrytí kódu
- Testovací příkaz .NET CLI
- dotnet-coverage
- Ukázkový zdrojový kód