dotnet-testing-complex-object-comparison — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited dotnet-testing-complex-object-comparison (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.
當需要比對包含多層巢狀屬性的複雜物件時:
[Fact]
public void ComplexObject_深層結構比對_應完全相符()
{
var expected = new Order
{
Id = 1,
Customer = new Customer
{
Name = "John Doe",
Address = new Address
{
Street = "123 Main St",
City = "Seattle",
ZipCode = "98101"
}
},
Items = new[]
{
new OrderItem { ProductName = "Laptop", Quantity = 1, Price = 999.99m },
new OrderItem { ProductName = "Mouse", Quantity = 2, Price = 29.99m }
}
};
var actual = orderService.GetOrder(1);
// 深層物件比對
actual.Should().BeEquivalentTo(expected);
}處理物件之間存在循環參照的情況:
[Fact]
public void TreeStructure_循環參照_應正確處理()
{
// 建立具有父子雙向參照的樹狀結構
var parent = new TreeNode { Value = "Root" };
var child1 = new TreeNode { Value = "Child1", Parent = parent };
var child2 = new TreeNode { Value = "Child2", Parent = parent };
parent.Children = new[] { child1, child2 };
var actualTree = treeService.GetTree("Root");
// 處理循環參照
actualTree.Should().BeEquivalentTo(parent, options =>
options.IgnoringCyclicReferences()
.WithMaxRecursionDepth(10)
);
}AwesomeAssertions 還提供多種進階比對模式:動態欄位排除(排除時間戳記、自動生成欄位)、巢狀物件欄位排除、大量資料效能最佳化比對(選擇性屬性比對、抽樣驗證策略)、以及嚴格/寬鬆排序控制。
完整程式碼範例請參閱 references/detailed-comparison-patterns.md
| 選項方法 | 用途 | 適用場景 |
|---|---|---|
Excluding(x => x.Property) | 排除特定屬性 | 排除時間戳記、自動生成欄位 |
Including(x => x.Property) | 只包含特定屬性 | 關鍵屬性驗證 |
IgnoringCyclicReferences() | 忽略循環參照 | 樹狀結構、雙向關聯 |
WithMaxRecursionDepth(n) | 限制遞迴深度 | 深層巢狀結構 |
WithStrictOrdering() | 嚴格順序比對 | 陣列/集合順序重要時 |
WithoutStrictOrdering() | 寬鬆順序比對 | 陣列/集合順序不重要時 |
WithTracing() | 啟用追蹤 | 除錯複雜比對失敗 |
[Fact]
public void EFEntity_資料庫實體_應排除導航屬性()
{
var expected = new Product { Id = 1, Name = "Laptop", Price = 999 };
var actual = dbContext.Products.Find(1);
actual.Should().BeEquivalentTo(expected, options =>
options.ExcludingMissingMembers() // 排除 EF 追蹤屬性
.Excluding(p => p.CreatedAt)
.Excluding(p => p.UpdatedAt)
);
}[Fact]
public void ApiResponse_JSON反序列化_應忽略額外欄位()
{
var expected = new UserDto
{
Id = 1,
Username = "john_doe"
};
var response = await httpClient.GetAsync("/api/users/1");
var actual = await response.Content.ReadFromJsonAsync<UserDto>();
actual.Should().BeEquivalentTo(expected, options =>
options.ExcludingMissingMembers() // 忽略 API 額外欄位
);
}[Fact]
public void Builder_測試資料_應匹配預期結構()
{
var expected = new OrderBuilder()
.WithId(1)
.WithCustomer("John Doe")
.WithItems(3)
.Build();
var actual = orderService.CreateOrder(orderRequest);
actual.Should().BeEquivalentTo(expected, options =>
options.Excluding(o => o.OrderNumber) // 系統生成
.Excluding(o => o.CreatedAt)
);
}[Fact]
public void Comparison_錯誤訊息_應清楚說明差異()
{
var expected = new User { Name = "John", Age = 30 };
var actual = userService.GetUser(1);
// 使用 because 參數提供上下文
actual.Should().BeEquivalentTo(expected, options =>
options.Excluding(u => u.Id)
.Because("ID 是系統自動生成的,不應納入比對")
);
}[Fact]
public void MultipleComparisons_批次驗證_應一次顯示所有失敗()
{
var users = userService.GetAllUsers();
using (new AssertionScope())
{
foreach (var user in users)
{
user.Id.Should().BeGreaterThan(0);
user.Name.Should().NotBeNullOrEmpty();
user.Email.Should().MatchRegex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$");
}
}
// 所有失敗會一起報告,而非遇到第一個失敗就停止
}此技能可與以下技能組合使用:
Excluding 更清楚IgnoringCyclicReferences() 明確處理A: 使用以下策略優化:
Including 只比對關鍵屬性WithMaxRecursionDepth 限制遞迴深度AssertKeyPropertiesOnly 快速比對關鍵欄位A: 通常由循環參照引起:
options.IgnoringCyclicReferences()
.WithMaxRecursionDepth(10)A: 使用路徑模式匹配:
options.Excluding(ctx => ctx.Path.EndsWith("At"))
.Excluding(ctx => ctx.Path.EndsWith("Time"))
.Excluding(ctx => ctx.Path.Contains("Timestamp"))A: 啟用詳細追蹤:
options.WithTracing() // 產生詳細的比對追蹤資訊本技能提供以下範本檔案:
templates/comparison-patterns.cs: 常見比對模式範例templates/exclusion-strategies.cs: 欄位排除策略與擴充方法IgnoringCyclicReferences() 和 WithMaxRecursionDepth(n) 的用法,因為深層巢狀物件經常會遇到循環參照問題本技能內容提煉自「老派軟體工程師的測試修練 - 30 天挑戰」系列文章:
awesome-assertions-guide - AwesomeAssertions 基礎與進階用法unit-test-fundamentals - 單元測試基礎~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.