dotnet-testing-advanced-xunit-upgrade-guide

xUnit 2.9.x 到 3.x 升級完整指南。當需要將 xUnit v2 升級至 v3 或了解 xUnit v3 新功能與破壞性變更時使用。涵蓋套件更新、async void 修正、IAsyncLifetime 調整。包含新功能介紹: Assert.Skip、Explicit Tests、Matrix Theory、Assembly Fixtures。 Make sure to use this skill whenever the user mentions xUnit upgrade, xUnit v3, xUnit migration, xUnit breaking changes, or Assert.Skip, even if they don't explicitly ask for xUnit upgrade guidance. Keywords: xunit upgrade, xunit v3, xunit 3.x, xunit migration, xunit 升級, xunit.v3, OutputType Exe, IAsyncLifetime v3, Assert.Skip, SkipUnless, SkipWhen, Explicit attribute, MatrixTheoryData, AssemblyFixture, 破壞性變更

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "dotnet-testing-advanced-xunit-upgrade-guide" with this command: npx skills add kevintsengtw/dotnet-testing-agent-skills/kevintsengtw-dotnet-testing-agent-skills-dotnet-testing-advanced-xunit-upgrade-guide

xUnit 升級指南:從 2.9.x 到 3.x

核心概念

套件命名變革

xUnit v3 採用全新的套件命名策略:

v1~v2 套件名稱v3 套件名稱說明
xunitxunit.v3主要測試框架
xunit.assertxunit.v3.assert斷言函式庫
xunit.corexunit.v3.core核心元件
xunit.abstractions(移除)不再需要
xunit.runner.visualstudioxunit.runner.visualstudio (3.x.y)測試執行器

重要:使用 xunit.v3 套件名稱,不是 xunit

最低運行時需求

xUnit 3.x 的嚴格要求:

  • .NET Framework 4.7.2+
  • .NET 8.0+ (推薦)

不支援的版本

  • .NET Core 3.1
  • .NET 5、6、7

破壞性變更清單

1. 測試專案變成可執行檔

<!-- xUnit 2.x (Library) -->
<PropertyGroup>
  <OutputType>Library</OutputType>
</PropertyGroup>

<!-- xUnit 3.x (Exe) - 必須變更 -->
<PropertyGroup>
  <OutputType>Exe</OutputType>
</PropertyGroup>

2. async void 測試不再支援

// ❌ xUnit 2.x - 3.x 中會失敗
[Fact]
public async void 測試某個非同步功能()
{
    var result = await SomeAsyncMethod();
    Assert.True(result);
}

// ✅ xUnit 3.x - 正確寫法
[Fact]
public async Task 測試某個非同步功能()
{
    var result = await SomeAsyncMethod();
    Assert.True(result);
}

3. IAsyncLifetime 變更

在 xUnit 3.x 中,IAsyncLifetime 繼承 IAsyncDisposable。如果同時實作 IAsyncLifetimeIDisposable,只會呼叫 DisposeAsync,不會呼叫 Dispose

// ⚠️ 需要注意的模式
public class MyTestClass : IAsyncLifetime, IDisposable
{
    public async Task InitializeAsync() { /* ... */ }
    public async Task DisposeAsync() { /* 會被呼叫 */ }
    public void Dispose() { /* 在 3.x 中不會被呼叫 */ }
}

// ✅ 建議:將清理邏輯統一放在 DisposeAsync
public class MyTestClass : IAsyncLifetime
{
    public async Task InitializeAsync() { /* 初始化 */ }
    public async Task DisposeAsync() { /* 所有清理邏輯 */ }
}

4. SkippableFact/SkippableTheory 移除

// ❌ xUnit 2.x - 已移除
[SkippableFact]
public void 可跳過的測試()
{
    Skip.If(某個條件, "跳過原因");
    // 測試邏輯
}

// ✅ xUnit 3.x - 使用 Assert.Skip
[Fact]
public void 可跳過的測試()
{
    if (某個條件)
    {
        Assert.Skip("跳過原因");
    }
    // 測試邏輯
}

5. 僅支援 SDK-style 專案

檢查專案檔案開頭是否為:

<Project Sdk="Microsoft.NET.Sdk">

如果是傳統格式,必須先轉換為 SDK-style。


升級步驟

步驟 1:建立升級分支

git checkout -b feature/upgrade-xunit-v3

步驟 2:更新專案檔案

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <OutputType>Exe</OutputType>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <IsPackable>false</IsPackable>
    <IsTestProject>true</IsTestProject>
  </PropertyGroup>

  <ItemGroup>
    <!-- xUnit v3 套件 -->
    <PackageReference Include="xunit.v3" Version="3.0.1" />
    <PackageReference Include="xunit.runner.visualstudio" Version="3.1.4">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />

    <!-- 常用輔助套件 -->
    <PackageReference Include="AwesomeAssertions" Version="8.1.0" />
    <PackageReference Include="NSubstitute" Version="5.3.0" />
  </ItemGroup>
</Project>

步驟 3:修正 async void 測試

使用 IDE 搜尋:

async\s+void.*\[(Fact|Theory)\]

將所有 async void 改為 async Task

步驟 4:更新 using 陳述式

// 移除 (不再需要)
// using Xunit.Abstractions;

// 保留
using Xunit;

步驟 5:編譯與測試

dotnet clean
dotnet restore
dotnet build
dotnet test --verbosity normal

xUnit 3.x 新功能

動態跳過測試

聲明式 (SkipUnless/SkipWhen)

[Fact(SkipUnless = nameof(IsWindowsEnvironment),
      Skip = "此測試只在 Windows 環境執行")]
public void 只在Windows上執行的測試()
{
    // 測試邏輯
}

public static bool IsWindowsEnvironment =>
    RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

命令式 (Assert.Skip)

[Fact]
public void 根據環境變數跳過的測試()
{
    var enableTests = Environment.GetEnvironmentVariable("ENABLE_INTEGRATION_TESTS");

    if (string.IsNullOrEmpty(enableTests) || enableTests.ToLower() != "true")
    {
        Assert.Skip("整合測試已停用。設定 ENABLE_INTEGRATION_TESTS=true 來執行");
    }

    // 測試邏輯...
}

明確測試 (Explicit Tests)

[Fact(Explicit = true)]
public void 昂貴的整合測試()
{
    // 這個測試預設不會執行,除非明確要求
    // 適用於效能測試、長時間執行的測試
}

[Test] 屬性

// 三種寫法功能相同
[Test]
public void 使用Test屬性的測試() { Assert.True(true); }

[Fact]
public void 使用Fact屬性的測試() { Assert.True(true); }

矩陣理論資料 (Matrix Theory Data)

public static TheoryData<int, string> TestData =>
    new MatrixTheoryData<int, string>(
        [1, 2, 3],                    // 數字資料
        ["Hello", "World", "Test"]    // 字串資料
    );
    // 這會產生 3×3=9 個測試案例

[Theory]
[MemberData(nameof(TestData))]
public void 矩陣測試範例(int number, string text)
{
    number.Should().BePositive();
    text.Should().NotBeNullOrEmpty();
}

Assembly Fixtures

public class DatabaseAssemblyFixture : IAsyncLifetime
{
    public string ConnectionString { get; private set; }

    public async Task InitializeAsync()
    {
        // 建立測試資料庫
        ConnectionString = await CreateTestDatabaseAsync();
    }

    public async Task DisposeAsync()
    {
        // 清理測試資料庫
        await DropTestDatabaseAsync();
    }
}

// 註冊 Assembly Fixture
[assembly: AssemblyFixture(typeof(DatabaseAssemblyFixture))]

// 在測試中使用
public class UserServiceTests
{
    private readonly DatabaseAssemblyFixture _dbFixture;

    public UserServiceTests(DatabaseAssemblyFixture dbFixture)
    {
        _dbFixture = dbFixture;
    }

    [Fact]
    public void Test1() { /* 使用 _dbFixture.ConnectionString */ }
}

Test Pipeline Startup

public class TestPipelineStartup : ITestPipelineStartup
{
    public async Task ConfigureAsync(ITestPipelineBuilder builder,
                                     CancellationToken cancellationToken)
    {
        // 全域初始化邏輯
        Console.WriteLine("初始化測試環境...");
        await InitializeDatabaseAsync();
    }
}

// 註冊
[assembly: TestPipelineStartup(typeof(TestPipelineStartup))]

xunit.runner.json 設定

{
  "$schema": "https://xunit.net/schema/v3/xunit.runner.schema.json",
  "parallelAlgorithm": "conservative",
  "maxParallelThreads": 4,
  "diagnosticMessages": true,
  "internalDiagnosticMessages": false,
  "methodDisplay": "classAndMethod",
  "preEnumerateTheories": true,
  "stopOnFail": false
}

測試報告格式

xUnit 3.x 支援多種報告格式:

# 產生 CTRF 格式報告
dotnet run -- -ctrf results.json

# 產生 TRX 格式報告
dotnet run -- -trx results.trx

# 產生 XML 格式報告
dotnet run -- -xml results.xml

# 產生多種格式報告
dotnet run -- -xml results.xml -ctrf results.json -trx results.trx

常見問題與解決方案

問題 1:找不到 xunit.abstractions

錯誤The type or namespace name 'Abstractions' does not exist

解決:移除 using Xunit.Abstractions;,相關類型已移到 Xunit 命名空間。

問題 2:自訂 DataAttribute 無法運作

xUnit 3.x 中 DataAttribute 方法簽名已變更:GetData(MethodInfo)GetDataAsync(MethodInfo, DisposalTracker),回傳型別改為 Task<IReadOnlyCollection<ITheoryDataRow>>

問題 3:IDE 無法發現測試

確認 IDE 版本符合要求:

  • Visual Studio 2022 17.8+
  • Rider 2023.3+
  • VS Code (最新版)

如仍有問題,可暫時停用 Microsoft Testing Platform:

<PropertyGroup>
  <EnableMicrosoftTestingPlatform>false</EnableMicrosoftTestingPlatform>
</PropertyGroup>

升級檢查清單

升級前

  • 確認目標框架版本 (.NET 8+ 或 .NET Framework 4.7.2+)
  • 檢查專案檔案格式 (SDK-style)
  • 識別所有 async void 測試方法
  • 檢查 IAsyncLifetime 實作
  • 評估相依套件相容性
  • 建立備份分支

升級過程

  • 更新套件參考 (使用 xunit.v3)
  • 移除 xunit.abstractions 參考
  • 修改 OutputType 為 Exe
  • 修正所有 async void 測試方法
  • 更新 using 陳述式
  • 重構自訂屬性 (如有)
  • 驗證編譯成功
  • 執行所有測試

升級後驗證

  • 功能完整性測試
  • 效能基準比較
  • CI/CD Pipeline 驗證
  • 文檔更新
  • 團隊培訓

IDE 與工具支援

IDE 版本需求

IDE最低版本
Visual Studio2022 17.8+
VS Code最新版
Rider2023.3+

Microsoft Testing Platform

xUnit 3.x 預設啟用 Microsoft Testing Platform:

<PropertyGroup>
  <EnableMicrosoftTestingPlatform>true</EnableMicrosoftTestingPlatform>
  <OutputType>Exe</OutputType>
</PropertyGroup>

效能改進

xUnit 3.x 帶來的效能改進:

  1. 獨立進程執行:測試在獨立進程中執行,更好的隔離性
  2. 改進的並行演算法:更智慧的負載平衡
  3. 更快的啟動時間:可執行檔直接執行
  4. 更好的記憶體隔離:減少測試之間的干擾

輸出格式

  • 產生升級後的測試專案 .csproj 設定(xunit.v3 套件、OutputType Exe)
  • 包含 async void 修正為 async Task 的測試程式碼
  • 包含 IAsyncLifetime 調整與 SkippableFact 替換範例
  • 產生 xunit.runner.json 設定檔

參考資源

原始文章

本技能內容提煉自「老派軟體工程師的測試修練 - 30 天挑戰」系列文章:

官方文件

相關技能

  • dotnet-testing-xunit-project-setup - xUnit 專案設定基礎
  • dotnet-testing-advanced-tunit-fundamentals - TUnit 替代框架

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

dotnet-testing-code-coverage-analysis

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

dotnet-testing-advanced-webapi-integration-testing

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

dotnet-testing-unit-test-fundamentals

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

dotnet-testing-xunit-project-setup

No summary provided by upstream source.

Repository SourceNeeds Review