Source: kevintsengtw/dotnet-testing-agent-skills (MIT). Ported into dotnet-agent-harness.
AwesomeAssertions Fluent Assertion Guide
This skill provides a complete guide for writing high-quality test assertions using AwesomeAssertions, covering basic
syntax, advanced techniques, and best practices.
Applicable Scenarios
Use this skill when asked to perform the following tasks:
- Write clear, highly readable test assertions
- Compare complex objects or collection contents
- Verify exception throwing and messages
- Use fluent syntax (Should/Be/Contain) for test validation
- Replace native Assert with AwesomeAssertions
About AwesomeAssertions
AwesomeAssertions is a community fork version of FluentAssertions, using Apache 2.0 license, completely free
with no commercial usage restrictions.
Core Features
- Fully Free: Apache 2.0 license, suitable for commercial projects
- Fluent Syntax: Supports natural language style method chaining
- Rich Assertions: Covers objects, collections, strings, numbers, exceptions, and various other types
- Excellent Error Messages: Provides detailed and easy-to-understand failure information
- High Performance: Optimized implementation ensures test execution efficiency
- Extensible: Supports custom Assertion methods
Relationship with FluentAssertions
AwesomeAssertions is a community fork of FluentAssertions, main differences:
| Item |
FluentAssertions |
AwesomeAssertions |
| License |
Commercial projects require payment |
Apache 2.0 (completely free) |
| Namespace |
FluentAssertions |
AwesomeAssertions |
| API Compatibility |
Original |
Highly compatible |
| Community Support |
Official maintenance |
Community maintenance |
Installation and Setup
NuGet Package Installation
# .NET CLI
dotnet add package AwesomeAssertions
# Package Manager Console
Install-Package AwesomeAssertions
```text
### csproj Setup (Recommended)
```xml
<ItemGroup>
<PackageReference Include="AwesomeAssertions" Version="9.1.0" PrivateAssets="all" />
</ItemGroup>
```text
### Namespace Import
```csharp
using AwesomeAssertions;
using Xunit;
```text
---
## Core Assertions Syntax
All Assertions start with `.Should()`, combined with fluent method chaining.
| Category | Common Methods | Description |
|------|----------|------|
| **Object** | `NotBeNull()`, `BeOfType<T>()`, `BeEquivalentTo()` | Null, type, equality checks |
| **String** | `Contain()`, `StartWith()`, `MatchRegex()`, `BeEquivalentTo()` | Content, patterns, case-insensitive comparison |
| **Number** | `BeGreaterThan()`, `BeInRange()`, `BeApproximately()` | Comparison, range, floating point precision |
| **Collection** | `HaveCount()`, `Contain()`, `BeEquivalentTo()`, `AllSatisfy()` | Count, content, order, conditions |
| **Exception** | `Throw<T>()`, `NotThrow()`, `WithMessage()`, `WithInnerException()` | Exception types, messages, nested exceptions |
| **Async** | `ThrowAsync<T>()`, `CompleteWithinAsync()` | Async exceptions and completion validation |
> Full syntax examples and code please refer to [references/core-assertions-syntax.md](references/core-assertions-syntax.md)
---
## Advanced Techniques: Complex Object Comparison
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
- **Circular references**: `options.IgnoringCyclicReferences().WithMaxRecursionDepth(10)`
---
## Advanced Techniques: Custom Assertions Extension
Create domain-specific extension methods, like `product.Should().BeValidProduct()`, and reusable exclusion extensions like `ExcludingAuditFields()`.
Refer to [templates/custom-assertions-template.cs](templates/custom-assertions-template.cs) for complete implementation.
> Full examples please refer to [references/complex-object-assertions.md](references/complex-object-assertions.md)
---
## Performance Optimization Strategies
- **Large data**: First use `HaveCount()` for quick count check, then sample validation (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());
```text
---
## Best Practices and Team Standards
### Test Naming Conventions
Follow `Method_Scenario_ExpectedResult` pattern (e.g., `CreateUser_WithValidEmail_ShouldReturnEnabledUser`).
### Error Message Optimization
Add `because` string in assertions to provide clear failure context:
```csharp
result.IsSuccess.Should().BeFalse("because negative payment amounts are not allowed");
```text
### AssertionScope Usage
Use `AssertionScope` to collect multiple failure messages, display all problems 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");
}
```text
---
## Common Scenarios and Solutions
| Scenario | Key Technique |
|------|----------|
| API response validation | `BeEquivalentTo()` + `Including()` selective comparison |
| Database entity validation | `BeEquivalentTo()` + `Excluding()` exclude auto-generated fields |
| Event validation | Subscribe to capture events then validate properties one by one |
> Full code examples please refer to [references/common-scenarios.md](references/common-scenarios.md)
---
## Troubleshooting
### Problem 1: BeEquivalentTo fails but objects look the same
**Reason**: 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)
);
```text
### Problem 2: Collection order different causes failure
**Reason**: Collection order is different
**Solution**:
```csharp
// Use BeEquivalentTo ignore order
actual.Should().BeEquivalentTo(expected); // Does not check order
// Or explicitly specify need to check order
actual.Should().Equal(expected); // Checks order
```text
### Problem 3: Floating point comparison fails
**Reason**: Floating point precision issues
**Solution**:
```csharp
// Use precision tolerance
actualValue.Should().BeApproximately(expectedValue, 0.001);
```text
---
## When to Use This Skill
### Applicable Scenarios
Write unit tests or integration tests
Need to validate complex object structures
Compare API responses or database entities
Need clear failure messages
Establish domain-specific testing standards
### Not Applicable Scenarios
Performance testing (use dedicated benchmarking tools)
Load testing (use K6, JMeter, etc.)
UI testing (use Playwright, Selenium)
---
## Integration with Other Skills
### Integration with unit-test-fundamentals
First use `unit-test-fundamentals` to establish 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);
}
```text
### Integration with test-naming-conventions
Use `test-naming-conventions` naming conventions, combined with this skill's assertions:
```csharp
[Fact]
public void CreateUser_WithValidData_ShouldReturnEnabledUser()
{
var user = userService.CreateUser("test@example.com");
user.Should().NotBeNull()
.And.BeOfType<User>();
user.IsActive.Should().BeTrue();
}
```text
### Integration with xunit-project-setup
Install and use AwesomeAssertions in projects created with `xunit-project-setup`.
---
## Reference Resources
### Original Articles
This skill content is extracted from "Old School Software Engineer's Testing Practice - 30 Day Challenge" series:
- **Day 04 - AwesomeAssertions Basic Application and Practical Techniques**
- Ironman Article: https://ithelp.ithome.com.tw/articles/10374188
- Sample Code: https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day04
- **Day 05 - AwesomeAssertions Advanced Techniques and Complex Scenario Applications**
- Ironman Article: https://ithelp.ithome.com.tw/articles/10374425
- Sample Code: https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day05
### Official Resources
- **AwesomeAssertions GitHub**: https://github.com/AwesomeAssertions/AwesomeAssertions
- **AwesomeAssertions Official Documentation**: https://awesomeassertions.org/
### Related Articles
- **Fluent Assertions License Change Discussion**: https://www.dotblogs.com.tw/mrkt/2025/04/19/152408
---
## Summary
AwesomeAssertions provides powerful and readable assertion syntax, 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**: Establish domain-specific assertions
4. **Performance Optimization**: Handle large data scenarios
5. **Completely Free**: Apache 2.0 license with no commercial restrictions
Remember: Good assertions not only validate results but clearly express expected behavior and provide useful diagnostic information when failing.
Refer to [templates/assertion-examples.cs](templates/assertion-examples.cs) for more practical examples.
1---2name: dotnet-testing-awesome-assertions-guide3category: testing4subcategory: assertions5description: |6 Using AwesomeAssertions for fluent and readable test assertion skill. Used when writing clear assertions, comparing objects, validating collections, handling complex comparisons. Covers Should(), BeEquivalentTo(), Contain(), ThrowAsync() and complete API.7 Keywords: assertions, awesome assertions, fluent assertions, assertion, fluent assertion, Should(), Be(), BeEquivalentTo, Contain, ThrowAsync, NotBeNull, object comparison, collection validation, exception assertion, AwesomeAssertions, FluentAssertions, fluent syntax8targets: ['*']9license: MIT10metadata:11 author: Kevin Tseng12 version: '1.0.0'13 tags: '.NET, testing, AwesomeAssertions, FluentAssertions, assertions'14 related_skills: 'complex-object-comparison, fluentvalidation-testing, unit-test-fundamentals'15claudecode: {}16opencode: {}17codexcli:18 short-description: '.NET skill guidance for dotnet-testing-awesome-assertions-guide'19copilot: {}20geminicli: {}21antigravity: {}22---2324Source: kevintsengtw/dotnet-testing-agent-skills (MIT). Ported into dotnet-agent-harness.2526# AwesomeAssertions Fluent Assertion Guide2728This skill provides a complete guide for writing high-quality test assertions using AwesomeAssertions, covering basic29syntax, advanced techniques, and best practices.3031## Applicable Scenarios3233Use this skill when asked to perform the following tasks:3435- Write clear, highly readable test assertions36- Compare complex objects or collection contents37- Verify exception throwing and messages38- Use fluent syntax (Should/Be/Contain) for test validation39- Replace native Assert with AwesomeAssertions4041## About AwesomeAssertions4243**AwesomeAssertions** is a community fork version of FluentAssertions, using **Apache 2.0** license, completely free44with no commercial usage restrictions.4546### Core Features4748- Fully Free: Apache 2.0 license, suitable for commercial projects49- Fluent Syntax: Supports natural language style method chaining50- Rich Assertions: Covers objects, collections, strings, numbers, exceptions, and various other types51- Excellent Error Messages: Provides detailed and easy-to-understand failure information52- High Performance: Optimized implementation ensures test execution efficiency53- Extensible: Supports custom Assertion methods5455### Relationship with FluentAssertions5657AwesomeAssertions is a community fork of FluentAssertions, main differences:5859| Item | FluentAssertions | AwesomeAssertions |60| --------------------- | ----------------------------------- | ---------------------------- |61| **License** | Commercial projects require payment | Apache 2.0 (completely free) |62| **Namespace** | `FluentAssertions` | `AwesomeAssertions` |63| **API Compatibility** | Original | Highly compatible |64| **Community Support** | Official maintenance | Community maintenance |6566---6768## Installation and Setup6970### NuGet Package Installation7172````bash73# .NET CLI74dotnet add package AwesomeAssertions7576# Package Manager Console77Install-Package AwesomeAssertions78```text7980### csproj Setup (Recommended)8182```xml83<ItemGroup>84 <PackageReference Include="AwesomeAssertions" Version="9.1.0" PrivateAssets="all" />85</ItemGroup>86```text8788### Namespace Import8990```csharp91using AwesomeAssertions;92using Xunit;93```text9495---9697## Core Assertions Syntax9899All Assertions start with `.Should()`, combined with fluent method chaining.100101| Category | Common Methods | Description |102|------|----------|------|103| **Object** | `NotBeNull()`, `BeOfType<T>()`, `BeEquivalentTo()` | Null, type, equality checks |104| **String** | `Contain()`, `StartWith()`, `MatchRegex()`, `BeEquivalentTo()` | Content, patterns, case-insensitive comparison |105| **Number** | `BeGreaterThan()`, `BeInRange()`, `BeApproximately()` | Comparison, range, floating point precision |106| **Collection** | `HaveCount()`, `Contain()`, `BeEquivalentTo()`, `AllSatisfy()` | Count, content, order, conditions |107| **Exception** | `Throw<T>()`, `NotThrow()`, `WithMessage()`, `WithInnerException()` | Exception types, messages, nested exceptions |108| **Async** | `ThrowAsync<T>()`, `CompleteWithinAsync()` | Async exceptions and completion validation |109110> Full syntax examples and code please refer to [references/core-assertions-syntax.md](references/core-assertions-syntax.md)111112---113114## Advanced Techniques: Complex Object Comparison115116Use `BeEquivalentTo()` with `options` for deep object comparison:117118- **Exclude properties**: `options.Excluding(u => u.Id)` — exclude auto-generated fields119- **Dynamic exclusion**: `options.Excluding(ctx => ctx.Path.EndsWith("At"))` — exclude by pattern120- **Circular references**: `options.IgnoringCyclicReferences().WithMaxRecursionDepth(10)`121122---123124## Advanced Techniques: Custom Assertions Extension125126Create domain-specific extension methods, like `product.Should().BeValidProduct()`, and reusable exclusion extensions like `ExcludingAuditFields()`.127128Refer to [templates/custom-assertions-template.cs](templates/custom-assertions-template.cs) for complete implementation.129130> Full examples please refer to [references/complex-object-assertions.md](references/complex-object-assertions.md)131132---133134## Performance Optimization Strategies135136- **Large data**: First use `HaveCount()` for quick count check, then sample validation (avoid full `BeEquivalentTo`)137- **Selective comparison**: Use anonymous objects + `ExcludingMissingMembers()` to only validate key properties138139```csharp140// Selective property comparison — only validate key fields141order.Should().BeEquivalentTo(new142{143 CustomerId = 123,144 TotalAmount = 999.99m,145 Status = "Pending"146}, options => options.ExcludingMissingMembers());147```text148149---150151## Best Practices and Team Standards152153### Test Naming Conventions154155Follow `Method_Scenario_ExpectedResult` pattern (e.g., `CreateUser_WithValidEmail_ShouldReturnEnabledUser`).156157### Error Message Optimization158159Add `because` string in assertions to provide clear failure context:160161```csharp162result.IsSuccess.Should().BeFalse("because negative payment amounts are not allowed");163```text164165### AssertionScope Usage166167Use `AssertionScope` to collect multiple failure messages, display all problems at once:168169```csharp170using (new AssertionScope())171{172 user.Should().NotBeNull("User creation should not fail");173 user.Id.Should().BeGreaterThan(0, "User should have valid ID");174 user.Email.Should().NotBeNullOrEmpty("Email is required");175}176```text177178---179180## Common Scenarios and Solutions181182| Scenario | Key Technique |183|------|----------|184| API response validation | `BeEquivalentTo()` + `Including()` selective comparison |185| Database entity validation | `BeEquivalentTo()` + `Excluding()` exclude auto-generated fields |186| Event validation | Subscribe to capture events then validate properties one by one |187188> Full code examples please refer to [references/common-scenarios.md](references/common-scenarios.md)189190---191192## Troubleshooting193194### Problem 1: BeEquivalentTo fails but objects look the same195196**Reason**: May contain auto-generated fields or timestamps197198**Solution**:199200```csharp201// Exclude dynamic fields202actual.Should().BeEquivalentTo(expected, options => options203 .Excluding(x => x.Id)204 .Excluding(x => x.CreatedAt)205 .Excluding(x => x.UpdatedAt)206);207```text208209### Problem 2: Collection order different causes failure210211**Reason**: Collection order is different212213**Solution**:214215```csharp216// Use BeEquivalentTo ignore order217actual.Should().BeEquivalentTo(expected); // Does not check order218219// Or explicitly specify need to check order220actual.Should().Equal(expected); // Checks order221```text222223### Problem 3: Floating point comparison fails224225**Reason**: Floating point precision issues226227**Solution**:228229```csharp230// Use precision tolerance231actualValue.Should().BeApproximately(expectedValue, 0.001);232```text233234---235236## When to Use This Skill237238### Applicable Scenarios239240Write unit tests or integration tests241Need to validate complex object structures242Compare API responses or database entities243Need clear failure messages244Establish domain-specific testing standards245246### Not Applicable Scenarios247248Performance testing (use dedicated benchmarking tools)249Load testing (use K6, JMeter, etc.)250UI testing (use Playwright, Selenium)251252---253254## Integration with Other Skills255256### Integration with unit-test-fundamentals257258First use `unit-test-fundamentals` to establish test structure, then use this skill to write assertions:259260```csharp261[Fact]262public void Calculator_Add_TwoPositiveNumbers_ShouldReturnSum()263{264 // Arrange - follow 3A Pattern265 var calculator = new Calculator();266267 // Act268 var result = calculator.Add(2, 3);269270 // Assert - use AwesomeAssertions271 result.Should().Be(5);272}273```text274275### Integration with test-naming-conventions276277Use `test-naming-conventions` naming conventions, combined with this skill's assertions:278279```csharp280[Fact]281public void CreateUser_WithValidData_ShouldReturnEnabledUser()282{283 var user = userService.CreateUser("test@example.com");284285 user.Should().NotBeNull()286 .And.BeOfType<User>();287 user.IsActive.Should().BeTrue();288}289```text290291### Integration with xunit-project-setup292293Install and use AwesomeAssertions in projects created with `xunit-project-setup`.294295---296297## Reference Resources298299### Original Articles300301This skill content is extracted from "Old School Software Engineer's Testing Practice - 30 Day Challenge" series:302303- **Day 04 - AwesomeAssertions Basic Application and Practical Techniques**304 - Ironman Article: https://ithelp.ithome.com.tw/articles/10374188305 - Sample Code: https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day04306307- **Day 05 - AwesomeAssertions Advanced Techniques and Complex Scenario Applications**308 - Ironman Article: https://ithelp.ithome.com.tw/articles/10374425309 - Sample Code: https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day05310311### Official Resources312313- **AwesomeAssertions GitHub**: https://github.com/AwesomeAssertions/AwesomeAssertions314- **AwesomeAssertions Official Documentation**: https://awesomeassertions.org/315316### Related Articles317318- **Fluent Assertions License Change Discussion**: https://www.dotblogs.com.tw/mrkt/2025/04/19/152408319320---321322## Summary323324AwesomeAssertions provides powerful and readable assertion syntax, an important tool for writing high-quality tests. Through:3253261. **Fluent Syntax**: Makes test code more readable3272. **Rich Assertions**: Covers various data types3283. **Custom Extensions**: Establish domain-specific assertions3294. **Performance Optimization**: Handle large data scenarios3305. **Completely Free**: Apache 2.0 license with no commercial restrictions331332Remember: Good assertions not only validate results but clearly express expected behavior and provide useful diagnostic information when failing.333334Refer to [templates/assertion-examples.cs](templates/assertion-examples.cs) for more practical examples.335````