dotnet-testing-awesome-assertions-guide

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

AwesomeAssertions 流暢斷言指南

AwesomeAssertions Fluent Assertions Guide

本技能提供使用 AwesomeAssertions 進行高品質測試斷言的完整指南,涵蓋基礎語法、進階技巧與最佳實踐。
This skill provides a complete guide to writing high-quality test assertions with AwesomeAssertions, covering basic syntax, advanced techniques, and best practices.

適用情境

Use Cases

當被要求執行以下任務時,請使用此技能:
  • 撰寫清晰、可讀性高的測試斷言
  • 比對複雜物件或集合內容
  • 驗證例外狀況的拋出與訊息
  • 使用流暢語法(Should/Be/Contain)進行測試驗證
  • 將原生 Assert 替換為 AwesomeAssertions
Use this skill when you need to perform the following tasks:
  • Write clear, highly readable test assertions
  • Compare complex objects or collection contents
  • Verify exception throwing and messages
  • Perform test validation using fluent syntax (Should/Be/Contain)
  • Replace native Assert with AwesomeAssertions

關於 AwesomeAssertions

About AwesomeAssertions

AwesomeAssertions 是 FluentAssertions 的社群分支版本,使用 Apache 2.0 授權,完全免費且無商業使用限制。
AwesomeAssertions is a community fork of FluentAssertions, licensed under Apache 2.0, completely free with no commercial usage restrictions.

核心特色

Core Features

  • 完全免費:Apache 2.0 授權,適合商業專案使用
  • 🔗 流暢語法:支援方法鏈結的自然語言風格
  • 📦 豐富斷言:涵蓋物件、集合、字串、數值、例外等各種類型
  • 💬 優秀錯誤訊息:提供詳細且易理解的失敗資訊
  • 高性能:優化的實作確保測試執行效率
  • 🔧 可擴展:支援自訂 Assertions 方法
  • Completely Free: Apache 2.0 license, suitable for commercial projects
  • 🔗 Fluent Syntax: Supports method chaining in natural language style
  • 📦 Rich Assertions: Covers various types including objects, collections, strings, numbers, exceptions, etc.
  • 💬 Excellent Error Messages: Provides detailed and easy-to-understand failure information
  • High Performance: Optimized implementation ensures test execution efficiency
  • 🔧 Extensible: Supports custom Assertions methods

與 FluentAssertions 的關係

Relationship with FluentAssertions

AwesomeAssertions 是 FluentAssertions 的社群 fork,主要差異:
項目FluentAssertionsAwesomeAssertions
授權商業專案需付費Apache 2.0(完全免費)
命名空間
FluentAssertions
AwesomeAssertions
API 相容性原版高度相容
社群支援官方維護社群維護

AwesomeAssertions is a community fork of FluentAssertions. The main differences are:
ItemFluentAssertionsAwesomeAssertions
LicensePaid for commercial projectsApache 2.0 (completely free)
Namespace
FluentAssertions
AwesomeAssertions
API CompatibilityOriginal versionHighly compatible
Community SupportOfficially maintainedCommunity maintained

安裝與設定

Installation and Configuration

NuGet 套件安裝

NuGet Package Installation

bash
undefined
bash
undefined

.NET CLI

.NET CLI

dotnet add package AwesomeAssertions
dotnet add package AwesomeAssertions

Package Manager Console

Package Manager Console

Install-Package AwesomeAssertions
undefined
Install-Package AwesomeAssertions
undefined

csproj 設定(推薦)

csproj Configuration (Recommended)

xml
<ItemGroup>
  <PackageReference Include="AwesomeAssertions" Version="9.1.0" PrivateAssets="all" />
</ItemGroup>
xml
<ItemGroup>
  <PackageReference Include="AwesomeAssertions" Version="9.1.0" PrivateAssets="all" />
</ItemGroup>

命名空間引用

Namespace Reference

csharp
using AwesomeAssertions;
using Xunit;

csharp
using AwesomeAssertions;
using Xunit;

核心 Assertions 語法

Core Assertions Syntax

所有 Assertions 皆以
.Should()
開始,搭配流暢方法鏈結。
類別常用方法說明
物件
NotBeNull()
,
BeOfType<T>()
,
BeEquivalentTo()
空值、類型、相等性檢查
字串
Contain()
,
StartWith()
,
MatchRegex()
,
BeEquivalentTo()
內容、模式、忽略大小寫比對
數值
BeGreaterThan()
,
BeInRange()
,
BeApproximately()
比較、範圍、浮點精度
集合
HaveCount()
,
Contain()
,
BeEquivalentTo()
,
AllSatisfy()
數量、內容、順序、條件
例外
Throw<T>()
,
NotThrow()
,
WithMessage()
,
WithInnerException()
例外類型、訊息、巢狀例外
非同步
ThrowAsync<T>()
,
CompleteWithinAsync()
非同步例外與完成驗證
📖 完整語法範例與程式碼請參閱 references/core-assertions-syntax.md

All Assertions start with
.Should()
, paired with fluent method chaining.
CategoryCommon MethodsDescription
Object
NotBeNull()
,
BeOfType<T>()
,
BeEquivalentTo()
Null value, type, and equality checks
String
Contain()
,
StartWith()
,
MatchRegex()
,
BeEquivalentTo()
Content, pattern, and case-insensitive comparison
Number
BeGreaterThan()
,
BeInRange()
,
BeApproximately()
Comparison, range, and floating-point precision
Collection
HaveCount()
,
Contain()
,
BeEquivalentTo()
,
AllSatisfy()
Quantity, content, order, and condition checks
Exception
Throw<T>()
,
NotThrow()
,
WithMessage()
,
WithInnerException()
Exception type, message, and nested exception checks
Async
ThrowAsync<T>()
,
CompleteWithinAsync()
Async exception and completion validation
📖 For complete syntax examples and code, refer to references/core-assertions-syntax.md

進階技巧:複雜物件比對

Advanced Technique: Complex Object Comparison

使用
BeEquivalentTo()
搭配
options
進行深度物件比較:
  • 排除屬性
    options.Excluding(u => u.Id)
    — 排除自動生成欄位
  • 動態排除
    options.Excluding(ctx => ctx.Path.EndsWith("At"))
    — 按模式排除
  • 循環參考
    options.IgnoringCyclicReferences().WithMaxRecursionDepth(10)

Use
BeEquivalentTo()
with
options
for deep object comparison:
  • Exclude Properties:
    options.Excluding(u => u.Id)
    — Exclude auto-generated fields
  • Dynamic Exclusion:
    options.Excluding(ctx => ctx.Path.EndsWith("At"))
    — Exclude by pattern
  • Cyclic References:
    options.IgnoringCyclicReferences().WithMaxRecursionDepth(10)

進階技巧:自訂 Assertions 擴展

Advanced Technique: Custom Assertions Extension

建立領域特定擴展方法,如
product.Should().BeValidProduct()
,以及可重用排除擴展如
ExcludingAuditFields()
參考 templates/custom-assertions-template.cs 瞭解完整實作。
📖 完整範例請參閱 references/complex-object-assertions.md

Create domain-specific extension methods such as
product.Should().BeValidProduct()
, and reusable exclusion extensions like
ExcludingAuditFields()
.
Refer to templates/custom-assertions-template.cs for complete implementation.
📖 For complete examples, refer to references/complex-object-assertions.md

效能最佳化策略

Performance Optimization Strategies

  • 大量資料:先用
    HaveCount()
    快速檢查數量,再抽樣驗證(避免全量
    BeEquivalentTo
  • 選擇性比對:使用匿名物件 +
    ExcludingMissingMembers()
    只驗證關鍵屬性
csharp
// 選擇性屬性比對 — 只驗證關鍵欄位
order.Should().BeEquivalentTo(new
{
    CustomerId = 123,
    TotalAmount = 999.99m,
    Status = "Pending"
}, options => options.ExcludingMissingMembers());

  • Large Datasets: First use
    HaveCount()
    to quickly check quantity, then validate by sampling (avoid full
    BeEquivalentTo
    )
  • Selective Comparison: Use anonymous objects +
    ExcludingMissingMembers()
    to only validate key properties
csharp
// Selective property comparison — only validate key fields
order.Should().BeEquivalentTo(new
{
    CustomerId = 123,
    TotalAmount = 999.99m,
    Status = "Pending"
}, options => options.ExcludingMissingMembers());

最佳實踐與團隊標準

Best Practices and Team Standards

測試命名規範

Test Naming Conventions

遵循
方法_情境_預期結果
模式(如
CreateUser_有效電子郵件_應回傳啟用的使用者
)。
Follow the
Method_Scenario_ExpectedResult
pattern (e.g.,
CreateUser_ValidEmail_ShouldReturnEnabledUser
).

錯誤訊息優化

Error Message Optimization

在斷言中加入
because
字串,提供清晰的失敗上下文:
csharp
result.IsSuccess.Should().BeFalse("because negative payment amounts are not allowed");
Add a
because
string in assertions to provide clear failure context:
csharp
result.IsSuccess.Should().BeFalse("because negative payment amounts are not allowed");

AssertionScope 使用

Using AssertionScope

使用
AssertionScope
收集多個失敗訊息,一次顯示所有問題:
csharp
using (new AssertionScope())
{
    user.Should().NotBeNull("User creation should not fail");
    user.Id.Should().BeGreaterThan(0, "User should have valid ID");
    user.Email.Should().NotBeNullOrEmpty("Email is required");
}

Use
AssertionScope
to collect multiple failure messages and display all issues at once:
csharp
using (new AssertionScope())
{
    user.Should().NotBeNull("User creation should not fail");
    user.Id.Should().BeGreaterThan(0, "User should have valid ID");
    user.Email.Should().NotBeNullOrEmpty("Email is required");
}

常見情境與解決方案

Common Scenarios and Solutions

情境關鍵技巧
API 回應驗證
BeEquivalentTo()
+
Including()
選擇性比對
資料庫實體驗證
BeEquivalentTo()
+
Excluding()
排除自動生成欄位
事件驗證訂閱捕獲事件後逐一驗證屬性
📖 完整程式碼範例請參閱 references/common-scenarios.md

ScenarioKey Techniques
API Response Validation
BeEquivalentTo()
+
Including()
for selective comparison
Database Entity Validation
BeEquivalentTo()
+
Excluding()
to exclude auto-generated fields
Event ValidationCapture events via subscription and validate properties one by one
📖 For complete code examples, refer to references/common-scenarios.md

疑難排解

Troubleshooting

問題 1:BeEquivalentTo 失敗但物件看起來相同

Issue 1: BeEquivalentTo fails but objects look identical

原因:可能包含自動生成欄位或時間戳記
解決方案
csharp
// 排除動態欄位
actual.Should().BeEquivalentTo(expected, options => options
    .Excluding(x => x.Id)
    .Excluding(x => x.CreatedAt)
    .Excluding(x => x.UpdatedAt)
);
Cause: May contain auto-generated fields or timestamps
Solution:
csharp
// Exclude dynamic fields
actual.Should().BeEquivalentTo(expected, options => options
    .Excluding(x => x.Id)
    .Excluding(x => x.CreatedAt)
    .Excluding(x => x.UpdatedAt)
);

問題 2:集合順序不同導致失敗

Issue 2: Failure due to different collection order

原因:集合順序不同
解決方案
csharp
// 使用 BeEquivalentTo 忽略順序
actual.Should().BeEquivalentTo(expected); // 不檢查順序

// 或明確指定需要檢查順序
actual.Should().Equal(expected); // 檢查順序
Cause: Different collection order
Solution:
csharp
// Use BeEquivalentTo to ignore order
actual.Should().BeEquivalentTo(expected); // Does not check order

// Or explicitly specify that order needs to be checked
actual.Should().Equal(expected); // Checks order

問題 3:浮點數比較失敗

Issue 3: Floating-point comparison failure

原因:浮點數精度問題
解決方案
csharp
// 使用精度容差
actualValue.Should().BeApproximately(expectedValue, 0.001);

Cause: Floating-point precision issues
Solution:
csharp
// Use precision tolerance
actualValue.Should().BeApproximately(expectedValue, 0.001);

何時使用此技能

When to Use This Skill

適用情境

Suitable Scenarios

✅ 撰寫單元測試或整合測試時 ✅ 需要驗證複雜物件結構時 ✅ 比對 API 回應或資料庫實體時 ✅ 需要清晰的失敗訊息時 ✅ 建立領域特定測試標準時
✅ When writing unit tests or integration tests ✅ When you need to validate complex object structures ✅ When comparing API responses or database entities ✅ When you need clear failure messages ✅ When establishing domain-specific testing standards

不適用情境

Unsuitable Scenarios

❌ 效能測試(使用專用 benchmarking 工具) ❌ 負載測試(使用 K6、JMeter 等) ❌ UI 測試(使用 Playwright、Selenium)

❌ Performance testing (use dedicated benchmarking tools) ❌ Load testing (use K6, JMeter, etc.) ❌ UI testing (use Playwright, Selenium)

與其他技能的配合

Collaboration with Other Skills

與 unit-test-fundamentals 搭配

With unit-test-fundamentals

先使用
unit-test-fundamentals
建立測試結構,再使用本技能撰寫斷言:
csharp
[Fact]
public void Calculator_Add_兩個正數_應回傳總和()
{
    // Arrange - 遵循 3A Pattern
    var calculator = new Calculator();
    
    // Act
    var result = calculator.Add(2, 3);
    
    // Assert - 使用 AwesomeAssertions
    result.Should().Be(5);
}
First use
unit-test-fundamentals
to build the test structure, then use this skill to write assertions:
csharp
[Fact]
public void Calculator_Add_TwoPositiveNumbers_ShouldReturnSum()
{
    // Arrange - Follow 3A Pattern
    var calculator = new Calculator();
    
    // Act
    var result = calculator.Add(2, 3);
    
    // Assert - Use AwesomeAssertions
    result.Should().Be(5);
}

與 test-naming-conventions 搭配

With test-naming-conventions

使用
test-naming-conventions
的命名規範,搭配本技能的斷言:
csharp
[Fact]
public void CreateUser_有效資料_應回傳啟用使用者()
{
    var user = userService.CreateUser("test@example.com");
    
    user.Should().NotBeNull()
        .And.BeOfType<User>();
    user.IsActive.Should().BeTrue();
}
Use the naming conventions from
test-naming-conventions
paired with assertions from this skill:
csharp
[Fact]
public void CreateUser_ValidData_ShouldReturnEnabledUser()
{
    var user = userService.CreateUser("test@example.com");
    
    user.Should().NotBeNull()
        .And.BeOfType<User>();
    user.IsActive.Should().BeTrue();
}

與 xunit-project-setup 搭配

With xunit-project-setup

xunit-project-setup
建立的專案中安裝並使用 AwesomeAssertions。

Install and use AwesomeAssertions in projects set up with
xunit-project-setup
.

參考資源

Reference Resources

原始文章

Original Articles

本技能內容提煉自「老派軟體工程師的測試修練 - 30 天挑戰」系列文章:
This skill is extracted from the "Old-School Software Engineer's Test Training - 30-Day Challenge" series:

官方資源

Official Resources

相關文章

Related Articles



總結

Summary

AwesomeAssertions 提供了強大且可讀的斷言語法,是撰寫高品質測試的重要工具。透過:
  1. 流暢語法:讓測試程式碼更易讀
  2. 豐富斷言:涵蓋各種資料類型
  3. 自訂擴展:建立領域特定斷言
  4. 效能優化:處理大量資料情境
  5. 完全免費:Apache 2.0 授權無商業限制
記住:好的斷言不僅能驗證結果,更能清楚表達預期行為,並在失敗時提供有用的診斷資訊。
參考 templates/assertion-examples.cs 查看更多實用範例。
AwesomeAssertions provides a powerful and readable assertion syntax, which is an important tool for writing high-quality tests. Through:
  1. Fluent Syntax: Makes test code more readable
  2. Rich Assertions: Covers various data types
  3. Custom Extensions: Build domain-specific assertions
  4. Performance Optimization: Handle large dataset scenarios
  5. Completely Free: Apache 2.0 license with no commercial restrictions
Remember: Good assertions not only validate results but also clearly express expected behavior and provide useful diagnostic information when failures occur.
Refer to templates/assertion-examples.cs for more practical examples.