dotnet-testing-autofixture-nsubstitute-integration — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited dotnet-testing-autofixture-nsubstitute-integration (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.
Substitute.For<T>()# 核心套件
dotnet add package AutoFixture.AutoNSubstitute
# 相關套件(如尚未安裝)
dotnet add package AutoFixture
dotnet add package AutoFixture.Xunit2
dotnet add package NSubstitute
dotnet add package xunit| 套件名稱 | 用途 | NuGet 連結 |
|---|---|---|
AutoFixture.AutoNSubstitute | AutoFixture 與 NSubstitute 整合 | nuget.org |
AutoFixture.Xunit2 | xUnit 整合(AutoData 屬性) | nuget.org |
NSubstitute | 模擬框架 | nuget.org |
當在 AutoFixture 中加入 AutoNSubstituteCustomization 時,它會自動:
Substitute.For<T>() 建立 Mock 物件using AutoFixture;
using AutoFixture.AutoNSubstitute;
// 建立包含 AutoNSubstitute 功能的 Fixture
var fixture = new Fixture().Customize(new AutoNSubstituteCustomization());
// 自動建立服務和其相依性
// MyService 的所有介面相依性都會自動變成 NSubstitute 的替身
var service = fixture.Create<MyService>();[Frozen] 屬性用來控制測試中某個類型的實例:
[Frozen] 時,AutoFixture 會建立這個類別的一個實例並凍結它[Theory]
[AutoData]
public async Task TestMethod(
[Frozen] IRepository repository, // 這個 repository 會被凍結
MyService sut) // sut 會使用同一個 repository
{
// 設定凍結實例的行為
repository.GetAsync(Arg.Any<int>()).Returns(someData);
// SUT 內部使用的是同一個 repository 實例
var result = await sut.DoSomething();
}使用 [Frozen] 時,參數順序非常重要:
// 正確:Frozen 參數在 SUT 之前
public async Task TestMethod(
[Frozen] IRepository repository,
MyService sut)
// 錯誤:SUT 會使用不同的 repository 實例
public async Task TestMethod(
MyService sut,
[Frozen] IRepository repository) // 太晚凍結了[Fact]
public async Task TraditionalWay()
{
// Arrange - 手動建立每個相依性
var repository = Substitute.For<IRepository>();
var logger = Substitute.For<ILogger<OrderService>>();
var notificationService = Substitute.For<INotificationService>();
var cacheService = Substitute.For<ICacheService>();
var sut = new OrderService(repository, logger, notificationService, cacheService);
// 設定替身行為
repository.GetOrderAsync(Arg.Any<int>()).Returns(someOrder);
// Act
var result = await sut.GetOrderAsync(orderId);
// Assert
result.Should().NotBeNull();
}問題:
Substitute.For<T>() 呼叫[Theory]
[AutoDataWithCustomization]
public async Task WithAutoNSubstitute(
[Frozen] IRepository repository,
OrderService sut)
{
// Arrange - 相依性已自動建立,只需設定需要的行為
repository.GetOrderAsync(Arg.Any<int>()).Returns(someOrder);
// Act
var result = await sut.GetOrderAsync(orderId);
// Assert
result.Should().NotBeNull();
}優勢:
在實際專案中,通常需要整合多種客製化設定:
using AutoFixture;
using AutoFixture.AutoNSubstitute;
using AutoFixture.Xunit2;
namespace MyProject.Tests.AutoFixtureConfigurations;
/// <summary>
/// 包含客製化設定的 AutoData 屬性
/// </summary>
public class AutoDataWithCustomizationAttribute : AutoDataAttribute
{
/// <summary>
/// 建構函式
/// </summary>
public AutoDataWithCustomizationAttribute() : base(CreateFixture)
{
}
private static IFixture CreateFixture()
{
var fixture = new Fixture()
.Customize(new AutoNSubstituteCustomization())
.Customize(new MapsterMapperCustomization()) // 專案特定設定
.Customize(new DomainCustomization()); // 領域模型設定
return fixture;
}
}用於結合固定測試值與自動產生物件:
using AutoFixture;
using AutoFixture.AutoNSubstitute;
using AutoFixture.Xunit2;
namespace MyProject.Tests.AutoFixtureConfigurations;
/// <summary>
/// 包含客製化設定的 InlineAutoData 屬性
/// </summary>
public class InlineAutoDataWithCustomizationAttribute : InlineAutoDataAttribute
{
/// <summary>
/// 建構函式
/// </summary>
/// <param name="values">固定值(將填入測試方法的前幾個參數)</param>
public InlineAutoDataWithCustomizationAttribute(params object[] values)
: base(new AutoDataWithCustomizationAttribute(), values)
{
}
}為什麼使用 `new AutoDataWithCustomizationAttribute()` 而不是 `CreateFixture` 方法?
// 錯誤:InlineAutoDataAttribute 需要 AutoDataAttribute,不是 Func<IFixture>
public InlineAutoDataWithCustomizationAttribute(params object[] values)
: base(CreateFixture, values) // 編譯錯誤或行為異常
// 正確:傳遞 AutoDataAttribute 實例
public InlineAutoDataWithCustomizationAttribute(params object[] values)
: base(new AutoDataWithCustomizationAttribute(), values)原因:
InlineAutoDataAttribute 繼承自 CompositeDataAttributeAutoDataAttribute 實例作為資料來源提供者AutoDataWithCustomizationAttribute 的所有設定某些相依性(如 IMapper)不適合使用 Mock,而應該使用真實實例。包含 Mapster 和 AutoMapper 的客製化範例。
完整客製化處理範例請參考 references/dependency-customization.md
涵蓋基本測試、Frozen 相依行為設定、自動產生測試資料、InlineAutoData 參數化測試、CollectionSize 控制、IFixture 複雜資料設定、Nullable 參考類型處理等完整範例。
完整測試實作範例請參考 references/test-implementation-examples.md
| 場景 | 原因 |
|---|---|
| 服務層測試 | 通常有多個相依性,自動模擬效益最大 |
| 複雜相依圖 | AutoFixture 自動處理多層相依性 |
| 參數化測試 | 結合固定值與自動產生資料 |
| 需要大量測試資料 | 減少手動建立測試資料的工作 |
| 快速迭代開發 | 建構函式變更時測試通常不需修改 |
| 場景 | 原因 |
|---|---|
| 單一相依性測試 | 手動建立可能更清晰直覺 |
| 精確控制屬性值 | 需要額外的 fixture.Build().With() 設定 |
| 團隊不熟悉 AutoFixture | 學習成本可能影響開發效率 |
| 除錯困難的場景 | 自動產生的物件可能讓除錯變複雜 |
| 效能敏感的測試 | 物件建立的開銷可能影響執行速度 |
MyProject.Tests/
├── AutoFixtureConfigurations/
│ ├── AutoDataWithCustomizationAttribute.cs
│ ├── InlineAutoDataWithCustomizationAttribute.cs
│ ├── AutoMapperCustomization.cs
│ └── DomainCustomization.cs
├── Services/
│ ├── OrderServiceTests.cs
│ └── ShipperServiceTests.cs
└── ...[專案名稱]AutoDataAttribute 或 AutoDataWithCustomizationAttribute[功能]Customization(如 MapsterMapperCustomization)方法_情境_預期 的命名模式 // Frozen 參數在 SUT 之後,不會生效
public void Test(MyService sut, [Frozen] IRepository repo)
// Frozen 參數必須在 SUT 之前
public void Test([Frozen] IRepository repo, MyService sut) // 沒有 AutoNSubstitute,介面會產生異常
var fixture = new Fixture();
// 加入 AutoNSubstituteCustomization
var fixture = new Fixture().Customize(new AutoNSubstituteCustomization()); // 測試意圖不明確
public void Test(Order order, Customer customer, MyService sut)
{
var result = sut.Process(order);
result.Should().NotBeNull(); // 驗證什麼?
}
// 明確控制關鍵屬性
public void Test(IFixture fixture, MyService sut)
{
var order = fixture.Build<Order>()
.With(o => o.Status, OrderStatus.Pending)
.Create();
var result = sut.Process(order);
result.Status.Should().Be(OrderStatus.Processed);
}[ClassData] 或 IClassFixture<T> 共享設定| 技能名稱 | 關聯說明 |
|---|---|
autofixture-basics | AutoFixture 基礎使用,本技能的前置知識 |
autofixture-customization | 自訂 Customization 的進階用法 |
autodata-xunit-integration | AutoData 屬性家族的完整說明 |
nsubstitute-mocking | NSubstitute 基礎,Mock 設定的詳細說明 |
AutoDataAttribute 衍生類別檔案(*AutoDataAttribute.cs)ICustomization 實作類別檔案(*Customization.cs)[Theory] 搭配自訂 AutoData 屬性[Frozen] 參數置於 SUT 參數之前Returns() 與 Received() 進行行為設定與驗證本技能內容提煉自「老派軟體工程師的測試修練 - 30 天挑戰」系列文章:
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.