紀錄使用 xUnit 測試的一些筆記
準備單元測試環境
# 查看專案安裝的 nuget 套件
dotnet list package
# 安裝 xunit 核心套件
dotnet add package xunit
# Visual Studio 及 dotnet 需要安裝下面兩個套件才能執行測試
dotnet add package Microsoft.NET.Test.Sdk
dotnet add package xunit.runner.visualstudio
單元測試範例、測試框架是否正確工作
using Xunit;
public class UnitTestDemo
{
[Fact]
public void TestSuccess()
{
Assert.True(true);
}
[Fact]
public void TestFail()
{
Assert.True(false);
}
}
執行測試
## 執行測試
dotnet test
理論 throey 與事實 fact 的比較與介紹
實際上 fact 就等同於其他測試框架的測試,沒有甚麼不同,但是如果是需要測試多個不同的輸入,卻也要有相同的結果,則可以利用 throey 來做測試,他實際上是為了在以前的單元測試框架下,因為要測試多組參數呼叫同一個方法的情況,可能會寫出多個不同名稱的測試,內容都是呼叫相同方法,只是在測試不同的傳入參數。就可以採用 throey 的方式來做測試。
[Theory]
[InlineData(3)]
[InlineData(5)]
public void MyFirst_Theory_IsOdd(int value)
{
Assert.True(IsOdd(value));
}
[Theory]
[InlineData(6)]
public void MyFirst_Theory_IsNotOdd(int value)
{
Assert.False(IsOdd(value));
}
如果不用 throey 要驗證這三個情況,就可能需要寫成三個 fact
[Fact]
public void MyFirstFactWithOddValue3()
{
Assert.True(IsOdd(3));
}
[Fact]
public void MyFirstFactWithOddValue5()
{
Assert.True(IsOdd(5));
}
[Fact]
public void MyFirstFactWithEvenValue6()
{
Assert.False(IsOdd(6));
}
這兩種寫法都是可以的,因為它們也都各有優缺點,關注的點也不太一樣,所以要看自己的需求來決定要用哪一種。
一般來說 fact 可以很明確的驗證一件事情,並且在發生錯誤的時候可以直接根據測試的名稱識別出錯誤的測試。 而 throey 比較適用於需要測試相同功能在不同輸入的情況下是否正常運作,並且避免撰寫過多的測試方法。
也可以理解為
- 當測試不會根據不同的輸入參數而改變行為,並且只需要驗證一個確定的行為時,可以採用 fact 較為合適
- 當需要驗證多種輸入參數的情況下,並且需要驗證的行為是相同的,可以採用 throey 較為合適
驗證多種輸入參數的時候不建議把多種行為也寫在同一個 throey
加入配置文件設定
官方配置設定說明的蠻清楚的,有需要可以參考官方文件進行設定,這邊用一個簡單的設定來示範
測試專案目錄下新增 xunit.runner.json
檔案
{
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
"methodDisplayOptions": "replaceUnderscoreWithSpace,useOperatorMonikers "
}
選擇該檔案在建置動作時複製到輸出目錄 (修改專案 csproj 檔)
<ItemGroup>
<Content Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
並行測試,並透過顯示驗證
首先先在測試中透過建構式注入 ITestOutputHelper
來輸出測試的訊息,預設的情況下, TestClass1 底下的兩個測試會一個接著一個的執行,用來驗證的單元測試執行的開始跟結束,都有紀錄時間,透過指定 logger 參數可以在 CLI 看到測試的進度及結果
dotnet test --logger "console;verbosity=detailed"
public class TestClass1
{
private readonly ITestOutputHelper _output;
public TestClass1(ITestOutputHelper output)
{
_output = output;
}
[Fact]
public void Test1()
{
_output.WriteLine("Test 1 begin at {0:HH:mm:ss}", DateTime.Now);
Thread.Sleep(3000);
_output.WriteLine("Test 1 end at {0:HH:mm:ss}", DateTime.Now);
}
[Fact]
public void Test2()
{
_output.WriteLine("Test 2 begin at {0:HH:mm:ss}", DateTime.Now);
Thread.Sleep(5000);
_output.WriteLine("Test 2 end at {0:HH:mm:ss}", DateTime.Now);
}
}
預設情況下,每一個測試類別都是一個唯一的測試集合,這些測試之間並不會同時執行,但如果將它們放在不同的測試類別當中,就能夠同時進行測試
public class TestClass2A
{
private readonly ITestOutputHelper _output;
public TestClass2A(ITestOutputHelper output)
{
_output = output;
}
[Fact]
public void Test1()
{
_output.WriteLine("Test 2A begin at {0:HH:mm:ss}", DateTime.Now);
Thread.Sleep(3000);
_output.WriteLine("Test 2A end at {0:HH:mm:ss}", DateTime.Now);
}
}
public class TestClass2B
{
private readonly ITestOutputHelper _output;
public TestClass2B(ITestOutputHelper output)
{
_output = output;
}
[Fact]
public void Test1()
{
_output.WriteLine("Test 2B begin at {0:HH:mm:ss}", DateTime.Now);
Thread.Sleep(5000);
_output.WriteLine("Test 2B end at {0:HH:mm:ss}", DateTime.Now);
}
}
❯ dotnet test --logger "console;verbosity=detailed" 正在判斷要還原的專案... 所有專案都在最新狀態,可進行還原。 C:\Program Files\dotnet\sdk\8.0.100-preview.7.23376.3\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.RuntimeIdentifierInference.targets(314,5): message NETSDK1057: 您目前使用的是 .NET 預覽版。請參閱: https://aka.ms/dotnet-support-policy [D:\Code\GitLabCE\MyProject\MyProject.csproj] MyProject -> D:\Code\GitLabCE\MyProject\bin\Debug\net7.0\MyProject.dll D:\Code\GitLabCE\MyProject\bin\Debug\net7.0\MyProject.dll 的測試回合 (.NETCoreApp,Version=v7.0) Microsoft (R) Test Execution Command Line Tool 17.7.0-preview-23317-01+919ec8358820228cc5fa77ef000051c1d6875399 (x64) 版Copyright (C) Microsoft Corporation. 著作權所有,並保留一切權利。 正在啟動測試執行,請稍候... 總共有 1 個測試檔案與指定的模式相符。 D:\Code\GitLabCE\MyProject\bin\Debug\net7.0\MyProject.dll [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.5.0.1+5ebf84cd75 (64-bit .NET 7.0.5) [xUnit.net 00:00:00.06] Discovering: MyProject [xUnit.net 00:00:00.08] Discovered: MyProject [xUnit.net 00:00:00.08] Starting: MyProject 已通過 MyProject.TestClass2A.Test1 [3 s] 標準輸出訊息: Test 2A begin at 15:44:50 Test 2A end at 15:44:53 已通過 MyProject.TestClass2B.Test1 [5 s] 標準輸出訊息: Test 2B begin at 15:44:50 Test 2B end at 15:44:55 已通過 MyProject.TestClass1.Test2 [5 s] 標準輸出訊息: Test 2 begin at 15:44:50 Test 2 end at 15:44:55 [xUnit.net 00:00:08.15] Finished: MyProject 已通過 MyProject.TestClass1.Test1 [3 s] 標準輸出訊息: Test 1 begin at 15:44:55 Test 1 end at 15:44:58 測試回合成功。 測試數總計: 4 通過: 4 時間總計: 8.5914 秒
在 Visual Studio 2022, Rider, CLI 環境都是相同的
從 MSTest 到 xUnit
請參閱官方文件 基本上就是
- 替換 nuget package
- 修正一些 mstest 的標籤,改成用 xunit 的語法
- 可以依照警告來逐步修正,修正完畢後可以移除掉向後兼容的暫時用的套件
xunit.MSTest