xiaohongshu
xiaohongshu
dotnet-testing-advanced-xunit-upgrade-guide
xUnit 2.9.x 到 3.x 升級完整指南。涵蓋破壞性變更、套件更新、async void 修正、IAsyncLifetime 調整。包含新功能介紹: Assert.Skip、Explicit Tests、Matrix Theory、Assembly Fixtures。 Keywords: xunit upgrade, xunit v3, xunit 3.x, xunit migration, xunit 升級, xunit.v3, OutputType Exe, IAsyncLifetime v3, Assert.Skip, SkipUnless, SkipWhen, Expli...
Full skill instructions
當被要求執行以下任務時,請使用此技能:
xUnit v3 採用全新的套件命名策略:
| v1~v2 套件名稱 | v3 套件名稱 | 說明 |
|---|---|---|
xunit | xunit.v3 | 主要測試框架 |
xunit.assert | xunit.v3.assert | 斷言函式庫 |
xunit.core | xunit.v3.core | 核心元件 |
xunit.abstractions | (移除) | 不再需要 |
xunit.runner.visualstudio | xunit.runner.visualstudio (3.x.y) | 測試執行器 |
重要:使用 xunit.v3 套件名稱,不是 xunit。
xUnit 3.x 的嚴格要求:
不支援的版本:
<!-- xUnit 2.x (Library) -->
<PropertyGroup>
<OutputType>Library</OutputType>
</PropertyGroup>
<!-- xUnit 3.x (Exe) - 必須變更 -->
<PropertyGroup>
<OutputType>Exe</OutputType>
</PropertyGroup>
// ❌ 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);
}
在 xUnit 3.x 中,IAsyncLifetime 繼承 IAsyncDisposable。如果同時實作 IAsyncLifetime 和 IDisposable,只會呼叫 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() { /* 所有清理邏輯 */ }
}
// ❌ xUnit 2.x - 已移除
[SkippableFact]
public void 可跳過的測試()
{
Skip.If(某個條件, "跳過原因");
// 測試邏輯
}
// ✅ xUnit 3.x - 使用 Assert.Skip
[Fact]
public void 可跳過的測試()
{
if (某個條件)
{
Assert.Skip("跳過原因");
}
// 測試邏輯
}
檢查專案檔案開頭是否為:
<Project Sdk="Microsoft.NET.Sdk">
如果是傳統格式,必須先轉換為 SDK-style。
git checkout -b feature/upgrade-xunit-v3
<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>
使用 IDE 搜尋:
async\s+void.*\[(Fact|Theory)\]
將所有 async void 改為 async Task。
// 移除 (不再需要)
// using Xunit.Abstractions;
// 保留
using Xunit;
dotnet clean
dotnet restore
dotnet build
dotnet test --verbosity normal
聲明式 (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 來執行");
}
// 測試邏輯...
}
[Fact(Explicit = true)]
public void 昂貴的整合測試()
{
// 這個測試預設不會執行,除非明確要求
// 適用於效能測試、長時間執行的測試
}
// 三種寫法功能相同
[Test]
public void 使用Test屬性的測試() { Assert.True(true); }
[Fact]
public void 使用Fact屬性的測試() { Assert.True(true); }
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();
}
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 */ }
}
public class TestPipelineStartup : ITestPipelineStartup
{
public async Task ConfigureAsync(ITestPipelineBuilder builder,
CancellationToken cancellationToken)
{
// 全域初始化邏輯
Console.WriteLine("初始化測試環境...");
await InitializeDatabaseAsync();
}
}
// 註冊
[assembly: TestPipelineStartup(typeof(TestPipelineStartup))]
{
"$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
錯誤:The type or namespace name 'Abstractions' does not exist
解決:移除 using Xunit.Abstractions;,相關類型已移到 Xunit 命名空間。
// ❌ xUnit 2.x 的實作
public class CustomDataAttribute : DataAttribute
{
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
{
// 舊的實作
}
}
// ✅ xUnit 3.x 的實作
public class CustomDataAttribute : DataAttribute
{
public override async Task<IReadOnlyCollection<ITheoryDataRow>> GetDataAsync(
MethodInfo method,
DisposalTracker disposalTracker)
{
var data = await GenerateDataAsync();
return data.Select(item => new TheoryDataRow(item)).ToList();
}
}
確認 IDE 版本符合要求:
如仍有問題,可暫時停用 Microsoft Testing Platform:
<PropertyGroup>
<EnableMicrosoftTestingPlatform>false</EnableMicrosoftTestingPlatform>
</PropertyGroup>
xunit.v3)xunit.abstractions 參考| IDE | 最低版本 |
|---|---|
| Visual Studio | 2022 17.8+ |
| VS Code | 最新版 |
| Rider | 2023.3+ |
xUnit 3.x 預設啟用 Microsoft Testing Platform:
<PropertyGroup>
<EnableMicrosoftTestingPlatform>true</EnableMicrosoftTestingPlatform>
<OutputType>Exe</OutputType>
</PropertyGroup>
xUnit 3.x 帶來的效能改進:
本技能內容提煉自「老派軟體工程師的測試修練 - 30 天挑戰」系列文章:
請參考同目錄下的範例檔案:
templates/xunit-v3-project.csproj - xUnit 3.x 專案設定範本templates/upgrade-checklist.md - 升級檢查清單templates/code-migration-examples.cs - 程式碼遷移範例templates/new-features-examples.cs - 新功能使用範例xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience