dotnet-testing-advanced-tunit-advanced — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited dotnet-testing-advanced-tunit-advanced (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
TUnit 提供 MethodDataSource、ClassDataSource、Matrix Tests 三種進階資料來源。MethodDataSource 最靈活,支援動態產生與外部檔案載入;ClassDataSource 適合跨測試類別共享資料與 AutoFixture 整合;Matrix Tests 自動產生所有參數組合(注意控制數量避免爆炸性增長)。
完整範例與比較表請參閱 references/data-driven-testing.md
[Test]
[Property("Category", "Database")]
[Property("Priority", "High")]
public async Task DatabaseTest_高優先級_應能透過屬性過濾()
{
await Assert.That(true).IsTrue();
}
[Test]
[Property("Category", "Unit")]
[Property("Priority", "Medium")]
public async Task UnitTest_中等優先級_基本驗證()
{
await Assert.That(1 + 1).IsEqualTo(2);
}
[Test]
[Property("Category", "Integration")]
[Property("Priority", "Low")]
[Property("Environment", "Development")]
public async Task IntegrationTest_低優先級_僅開發環境執行()
{
await Assert.That("Hello World").Contains("World");
}public static class TestProperties
{
// 測試類別
public const string CATEGORY_UNIT = "Unit";
public const string CATEGORY_INTEGRATION = "Integration";
public const string CATEGORY_E2E = "E2E";
// 優先級
public const string PRIORITY_CRITICAL = "Critical";
public const string PRIORITY_HIGH = "High";
public const string PRIORITY_MEDIUM = "Medium";
public const string PRIORITY_LOW = "Low";
// 環境
public const string ENV_DEVELOPMENT = "Development";
public const string ENV_STAGING = "Staging";
public const string ENV_PRODUCTION = "Production";
}
[Test]
[Property("Category", TestProperties.CATEGORY_UNIT)]
[Property("Priority", TestProperties.PRIORITY_HIGH)]
public async Task ExampleTest_使用常數_確保一致性()
{
await Assert.That(1 + 1).IsEqualTo(2);
}TUnit 使用 dotnet run 而不是 dotnet test:
# 只執行單元測試
dotnet run --treenode-filter "/*/*/*/*[Category=Unit]"
# 只執行高優先級測試
dotnet run --treenode-filter "/*/*/*/*[Priority=High]"
# 組合條件:執行高優先級的單元測試
dotnet run --treenode-filter "/*/*/*/*[(Category=Unit)&(Priority=High)]"
# 或條件:執行單元測試或冒煙測試
dotnet run --treenode-filter "/*/*/*/*[(Category=Unit)|(Suite=Smoke)]"
# 執行特定功能的測試
dotnet run --treenode-filter "/*/*/*/*[Feature=OrderProcessing]"過濾語法注意事項:
/*/*/*/* 代表 Assembly/Namespace/Class/Method 層級TUnit 提供完整的生命週期鉤子:[Before(Class)] → 建構式 → [Before(Test)] → 測試方法 → [After(Test)] → Dispose → [After(Class)]。另有 Assembly/TestSession 層級與 [BeforeEvery]/[AfterEvery] 全域鉤子。建構式永遠最先執行,BeforeClass/AfterClass 各只執行一次。
完整屬性家族與範例請參閱 references/lifecycle-management.md
TUnit 的依賴注入建構在 Data Source Generators 基礎上:
public class MicrosoftDependencyInjectionDataSourceAttribute : DependencyInjectionDataSourceAttribute<IServiceScope>
{
private static readonly IServiceProvider ServiceProvider = CreateSharedServiceProvider();
public override IServiceScope CreateScope(DataGeneratorMetadata dataGeneratorMetadata)
{
return ServiceProvider.CreateScope();
}
public override object? Create(IServiceScope scope, Type type)
{
return scope.ServiceProvider.GetService(type);
}
private static IServiceProvider CreateSharedServiceProvider()
{
return new ServiceCollection()
.AddSingleton<IOrderRepository, MockOrderRepository>()
.AddSingleton<IDiscountCalculator, MockDiscountCalculator>()
.AddSingleton<IShippingCalculator, MockShippingCalculator>()
.AddSingleton<ILogger<OrderService>, MockLogger<OrderService>>()
.AddTransient<OrderService>()
.BuildServiceProvider();
}
}[MicrosoftDependencyInjectionDataSource]
public class DependencyInjectionTests(OrderService orderService)
{
[Test]
public async Task CreateOrder_使用TUnit依賴注入_應正確運作()
{
// Arrange - 依賴已經透過 TUnit DI 自動注入
var items = new List<OrderItem>
{
new() { ProductId = "PROD001", ProductName = "測試商品", UnitPrice = 100m, Quantity = 2 }
};
// Act
var order = await orderService.CreateOrderAsync("CUST001", CustomerLevel.VIP會員, items);
// Assert
await Assert.That(order).IsNotNull();
await Assert.That(order.CustomerId).IsEqualTo("CUST001");
await Assert.That(order.CustomerLevel).IsEqualTo(CustomerLevel.VIP會員);
}
[Test]
public async Task TUnitDependencyInjection_驗證自動注入_服務應為正確類型()
{
await Assert.That(orderService).IsNotNull();
await Assert.That(orderService.GetType().Name).IsEqualTo("OrderService");
}
}| 特性 | TUnit DI | 手動依賴建立 |
|---|---|---|
| 設定複雜度 | 一次設定,重複使用 | 每個測試都需要手動建立 |
| 可維護性 | 依賴變更只需修改一個地方 | 需要修改所有使用的測試 |
| 一致性 | 與產品程式碼的 DI 一致 | 可能與實際應用程式不一致 |
| 測試可讀性 | 專注於測試邏輯 | 被依賴建立程式碼干擾 |
| 範圍管理 | 自動管理服務範圍 | 需要手動管理物件生命週期 |
| 錯誤風險 | 框架保證依賴正確注入 | 可能遺漏或錯誤建立某些依賴 |
Stopwatch 驗證 SLA{0} 參數插值,讓測試報告更貼近業務語言完整範例(Retry/Timeout/DisplayName)請參閱 references/execution-control.md
在 TUnit 中使用 WebApplicationFactory<Program> 進行 ASP.NET Core 整合測試,透過實作 IDisposable 管理生命週期。涵蓋 API 回應驗證、Content-Type 標頭檢查,以及效能基準與並行負載測試。
完整 WebApplicationFactory 整合與負載測試範例請參閱 references/aspnet-integration.md
使用 [Before(Assembly)] / [After(Assembly)] 在 Assembly 層級管理 PostgreSQL、Redis、Kafka 等多容器編排,搭配 NetworkBuilder 建立共用網路。容器僅啟動一次,大幅減少啟動時間與資源消耗,同時保持測試間的資料隔離。
完整多容器編排與全域共享範例請參閱 references/tunit-testcontainers.md
████████╗██╗ ██╗███╗ ██╗██╗████████╗
╚══██╔══╝██║ ██║████╗ ██║██║╚══██╔══╝
██║ ██║ ██║██╔██╗ ██║██║ ██║
██║ ██║ ██║██║╚██╗██║██║ ██║
██║ ╚██████╔╝██║ ╚████║██║ ██║
╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚═╝ ╚═╝
Engine Mode: SourceGenerated特色與優勢:
# 啟用反射模式
dotnet run -- --reflection
# 或設定環境變數
$env:TUNIT_EXECUTION_MODE = "reflection"
dotnet run適用場景:
<PropertyGroup>
<PublishAot>true</PublishAot>
</PropertyGroup>dotnet publish -c Release問題現象: 測試摘要: 總計: 0, 失敗: 0, 成功: 0
解決步驟:
<PropertyGroup>
<IsTestProject>true</IsTestProject>
</PropertyGroup>global using System;
global using System.Collections.Generic;
global using System.Linq;
global using System.Threading.Tasks;
global using TUnit.Core;
global using TUnit.Assertions;
global using TUnit.Assertions.Extensions;// 在 WebApi 專案的 Program.cs 最後加上
public partial class Program { } // 讓整合測試可以存取dotnet clean; dotnet build
dotnet test --verbosity normal問題:測試類別無法被發現
dotnet clean; dotnet build)問題:編譯時出現奇怪錯誤
# .editorconfig
tunit.enable_verbose_diagnostics = true<PropertyGroup>
<TUnitEnableVerboseDiagnostics>true</TUnitEnableVerboseDiagnostics>
</PropertyGroup>| 檔案名稱 | 說明 |
|---|---|
| data-source-examples.cs | MethodDataSource、ClassDataSource 範例 |
| matrix-tests-examples.cs | Matrix Tests 組合測試範例 |
| lifecycle-di-examples.cs | 生命週期管理與依賴注入範例 |
| execution-control-examples.cs | Retry、Timeout、DisplayName 範例 |
| aspnet-integration-tests.cs | ASP.NET Core 整合測試範例 |
| testcontainers-examples.cs | Testcontainers 基礎設施編排範例 |
本技能內容提煉自「老派軟體工程師的測試修練 - 30 天挑戰」系列文章:
dotnet-testing-advanced-tunit-fundamentals - TUnit 基礎(前置技能)dotnet-testing-advanced-aspnet-integration-testing - ASP.NET Core 整合測試dotnet-testing-advanced-testcontainers-database - Testcontainers 資料庫測試~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.