使用程式碼涵蓋範圍進行單元測試
重要
本文說明如何建立範例專案。 如果您已經有專案,您可以直接跳到程式碼涵蓋範圍工具一節。
單元測試有助於確保功能,並提供重構工作的驗證方法。 程式碼涵蓋範圍是由單元測試執行程式碼數量的度量,可以是行數、分支或方法。 例如,如果您有一個簡單的應用程式,其中只有兩個條件式程式碼分支 (分支 a和分支 b),則驗證條件式分支 a的單元測試會報告分支程式碼涵蓋範圍 50%。
本文討論使用 Coverlet 進行單元測試的程式碼涵蓋範圍,以及使用 ReportGenerator 產生報表。 雖然本文著重於 C# 和 xUnit 作為測試架構,但 MSTest 和 NUnit 也可以使用。 Coverlet 是 GitHub 上的開放原始碼專案,可為 C# 提供跨平台程式碼涵蓋範圍架構。 Coverlet 是 .NET Foundation 的一部分。 Coverlet 會收集 Cobertura 涵蓋範圍測試回合資料,用於產生報表。
此外,本文會詳細說明如何使用 Coverlet 測試回合收集的程式碼涵蓋範圍資訊來產生報告。 您可以使用 GitHub - ReportGenerator 上的另一個開放原始碼專案來產生報表。 ReportGenerator 會將 Cobertura 所產生的涵蓋範圍報表轉換成各種人類可讀取的報表格式。
本文以範例瀏覽器上提供的範例原始程式碼專案為基礎。
待測系統
「受測系統」是指您要撰寫單元測試的程式碼,這可能是物件、服務,或公開可測試功能的任何其他項目。 在本文中,您將建立用作受測系統的類別庫,以及兩個對應的單元測試專案。
建立類別庫
從名為 UnitTestingCodeCoverage
的新目錄中的命令提示字元,使用 dotnet new classlib
命令建立新的 .NET 標準類別庫:
dotnet new classlib -n Numbers
下列程式碼片段會定義簡單的 PrimeService
類別,提供功能來檢查數位是否為質數。 複製下列程式碼片段,並取代在 Numbers 目錄中自動建立的 Class1.cs 檔案內容。 將 Class1.cs 檔案重新命名為 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;
}
}
}
提示
值得一提的是,Numbers
類別庫已刻意新增至 System
命名空間。 這允許可以在沒有 using System;
命名空間宣告的情況下存取 System.Math。 如需詳細資訊,請參閱命名空間 (C# 參考)。
建立測試專案
使用 dotnet new xunit
命令,從相同的命令提示字元建立兩個新的 xUnit 測試專案 (.NET Core) 範本:
dotnet new xunit -n XUnit.Coverlet.Collector
dotnet new xunit -n XUnit.Coverlet.MSBuild
這兩個新建立的 xUnit 測試專案都需要加入 Numbers 類別庫的專案參考。 如此一來,測試專案就能夠存取 PrimeService 進行測試。 從命令提示字元中使用 dotnet add
命令:
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
MSBuild 專案會適當地命名,因為將取決於 coverlet.msbuild NuGet 套件。 執行 dotnet add package
命令來新增此套件相依性:
cd XUnit.Coverlet.MSBuild && dotnet add package coverlet.msbuild && cd ..
先前的命令會將目錄有效地變更為 MSBuild 測試專案,然後新增 NuGet 套件。 完成後會變更目錄,並逐步執行一個層級。
開啟這兩個 UnitTest1.cs 檔案,並以下列程式碼片段取代其內容。 將 UnitTest1.cs 檔案重新命名為 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");
}
}
建立解決方案
從命令提示字元中,建立新的解決方案來封裝類別庫和兩個測試專案。 使用 dotnet sln
命令:
dotnet new sln -n XUnit.Coverage
這會在 UnitTestingCodeCoverage 目錄中建立新的方案檔名稱 XUnit.Coverage
。 新增專案至方案根部。
使用 dotnet build
命令建置解決方案:
dotnet build
如果建置成功,則您已建立三個專案、適當參考的專案和套件,並正確更新原始程式碼。 做得好!
程式碼涵蓋範圍工具
程式碼涵蓋範圍工具有兩種類型:
- DataCollectors:DataCollectors 會監視測試執行,並收集測試回合的相關資訊。 它們會以 XML 和 JSON 等各種輸出格式報告收集到的資訊。 如需詳細資訊,請參閱您的第一個 DataCollector。
- 報表產生器:使用從測試回合收集的資料來產生報表,通常是樣式的 HTML。
本節中將著重於資料收集器工具。
.NET 包含內建的程式碼涵蓋範圍資料收集器,它也可以在 Visual Studio 中使用。 此資料收集器會產生二進位 .coverage 檔案,其可用來在 Visual Studio 中產生報告。 此二進位檔案不是人類可讀取的,它必須先將其轉換成人類可讀取的格式,然後才能用來在 Visual Studio 之外產生報告。
提示
dotnet-coverage
工具是一個跨平台工具,它可用來將二進位涵蓋範圍測試結果檔案轉換成人類可讀取的格式。 如需詳細資訊,請參閱 dotnet-coverage。
Coverlet 是一個內建收集器的開放原始碼替代方案。 它可將測試結果產生為人類可讀取的 Cobertura XML 檔案,然後它可用來產生 HTML 報告。 若要針對程式碼涵蓋範圍使用 Coverlet,現有的單元測試專案必須具有適當的套件相依性,或者依賴 .NET 全域工具和對應的 coverlet.console NuGet 套件。
與 .NET 測試整合
根據預設,xUnit 測試專案範本已與 coverlet.collector 整合。
從命令提示字元中,將目錄變更為 XUnit.Coverlet.Collector 專案,然後執行 dotnet test
命令:
cd XUnit.Coverlet.Collector && dotnet test --collect:"XPlat Code Coverage"
注意
"XPlat Code Coverage"
引數是對應至 Coverlet 中資料收集器的自訂名稱。 此名稱必要但不區分大小寫。 若要使用 .NET 的內建程式碼涵蓋範圍資料收集器,請使用 "Code Coverage"
。
在執行過程中 dotnet test
,產生的 coverage.cobertura.xml 檔案會輸出至 TestResults 目錄。 XML 檔案包含結果。 這是依賴 .NET CLI 的跨平台選項,非常適合無法使用 MSBuild 的組建系統。
以下是範例 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>
提示
或者,如果您的組建系統已經使用 MSBuild,您可以使用 MSBuild 套件。 從命令提示字元中,將目錄變更為 XUnit.Coverlet.MSBuild 專案,然後執行 dotnet test
命令:
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura
產生的 coverage.cobertura.xml 檔案為輸出。 您可以在這裡遵循 MSBuild 整合指南
產生報表
現在您可以從單元測試回合收集資料,您能使用 ReportGenerator 產生報表。 若要將 ReportGenerator NuGet 套件安裝為 .NET 全域工具,請使用 dotnet tool install
命令:
dotnet tool install -g dotnet-reportgenerator-globaltool
執行工具並提供所需的選項,因為輸出 coverage.cobertura.xml 檔案來自先前的測試回合。
reportgenerator
-reports:"Path\To\TestProject\TestResults\{guid}\coverage.cobertura.xml"
-targetdir:"coveragereport"
-reporttypes:Html
執行此命令之後,HTML 檔案代表產生的報表。
另請參閱
- Visual Studio 單元測試程式碼涵蓋範圍
- GitHub - Coverlet 存放庫
- GitHub - ReportGenerator 存放庫
- ReportGenerator 專案網站
- Azure:發佈程式碼涵蓋範圍結果
- Azure:檢閱程式碼涵蓋範圍結果
- .NET CLI 測試命令
- dotnet-coverage
- 範例原始程式碼