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-guide3description: 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. Keywords: assertions, awesome assertions, fluent assertions, assertion, fluent assertion, Should(), Be(), BeEquivalentTo, Contain, ThrowAsync, NotBeNull, object comparison, collection validation, exception assertion, AwesomeAssertions, FluentAssertions, fluent syntax4license: MIT5---67Source: kevintsengtw/dotnet-testing-agent-skills (MIT). Ported into dotnet-agent-harness.89# AwesomeAssertions Fluent Assertion Guide1011This skill provides a complete guide for writing high-quality test assertions using AwesomeAssertions, covering basic12syntax, advanced techniques, and best practices.1314## Applicable Scenarios1516Use this skill when asked to perform the following tasks:1718- Write clear, highly readable test assertions19- Compare complex objects or collection contents20- Verify exception throwing and messages21- Use fluent syntax (Should/Be/Contain) for test validation22- Replace native Assert with AwesomeAssertions2324## About AwesomeAssertions2526**AwesomeAssertions** is a community fork version of FluentAssertions, using **Apache 2.0** license, completely free27with no commercial usage restrictions.2829### Core Features3031- Fully Free: Apache 2.0 license, suitable for commercial projects32- Fluent Syntax: Supports natural language style method chaining33- Rich Assertions: Covers objects, collections, strings, numbers, exceptions, and various other types34- Excellent Error Messages: Provides detailed and easy-to-understand failure information35- High Performance: Optimized implementation ensures test execution efficiency36- Extensible: Supports custom Assertion methods3738### Relationship with FluentAssertions3940AwesomeAssertions is a community fork of FluentAssertions, main differences:4142| Item | FluentAssertions | AwesomeAssertions |43| --------------------- | ----------------------------------- | ---------------------------- |44| **License** | Commercial projects require payment | Apache 2.0 (completely free) |45| **Namespace** | `FluentAssertions` | `AwesomeAssertions` |46| **API Compatibility** | Original | Highly compatible |47| **Community Support** | Official maintenance | Community maintenance |4849---5051## Installation and Setup5253### NuGet Package Installation5455````bash56# .NET CLI57dotnet add package AwesomeAssertions5859# Package Manager Console60Install-Package AwesomeAssertions61```text6263### csproj Setup (Recommended)6465```xml66<ItemGroup>67 <PackageReference Include="AwesomeAssertions" Version="9.1.0" PrivateAssets="all" />68</ItemGroup>69```text7071### Namespace Import7273```csharp74using AwesomeAssertions;75using Xunit;76```text7778---7980## Core Assertions Syntax8182All Assertions start with `.Should()`, combined with fluent method chaining.8384| Category | Common Methods | Description |85|------|----------|------|86| **Object** | `NotBeNull()`, `BeOfType<T>()`, `BeEquivalentTo()` | Null, type, equality checks |87| **String** | `Contain()`, `StartWith()`, `MatchRegex()`, `BeEquivalentTo()` | Content, patterns, case-insensitive comparison |88| **Number** | `BeGreaterThan()`, `BeInRange()`, `BeApproximately()` | Comparison, range, floating point precision |89| **Collection** | `HaveCount()`, `Contain()`, `BeEquivalentTo()`, `AllSatisfy()` | Count, content, order, conditions |90| **Exception** | `Throw<T>()`, `NotThrow()`, `WithMessage()`, `WithInnerException()` | Exception types, messages, nested exceptions |91| **Async** | `ThrowAsync<T>()`, `CompleteWithinAsync()` | Async exceptions and completion validation |9293> Full syntax examples and code please refer to [references/core-assertions-syntax.md](references/core-assertions-syntax.md)9495---9697## Advanced Techniques: Complex Object Comparison9899Use `BeEquivalentTo()` with `options` for deep object comparison:100101- **Exclude properties**: `options.Excluding(u => u.Id)` — exclude auto-generated fields102- **Dynamic exclusion**: `options.Excluding(ctx => ctx.Path.EndsWith("At"))` — exclude by pattern103- **Circular references**: `options.IgnoringCyclicReferences().WithMaxRecursionDepth(10)`104105---106107## Advanced Techniques: Custom Assertions Extension108109Create domain-specific extension methods, like `product.Should().BeValidProduct()`, and reusable exclusion extensions like `ExcludingAuditFields()`.110111Refer to [templates/custom-assertions-template.cs](templates/custom-assertions-template.cs) for complete implementation.112113> Full examples please refer to [references/complex-object-assertions.md](references/complex-object-assertions.md)114115---116117## Performance Optimization Strategies118119- **Large data**: First use `HaveCount()` for quick count check, then sample validation (avoid full `BeEquivalentTo`)120- **Selective comparison**: Use anonymous objects + `ExcludingMissingMembers()` to only validate key properties121122```csharp123// Selective property comparison — only validate key fields124order.Should().BeEquivalentTo(new125{126 CustomerId = 123,127 TotalAmount = 999.99m,128 Status = "Pending"129}, options => options.ExcludingMissingMembers());130```text131132---133134## Best Practices and Team Standards135136### Test Naming Conventions137138Follow `Method_Scenario_ExpectedResult` pattern (e.g., `CreateUser_WithValidEmail_ShouldReturnEnabledUser`).139140### Error Message Optimization141142Add `because` string in assertions to provide clear failure context:143144```csharp145result.IsSuccess.Should().BeFalse("because negative payment amounts are not allowed");146```text147148### AssertionScope Usage149150Use `AssertionScope` to collect multiple failure messages, display all problems at once:151152```csharp153using (new AssertionScope())154{155 user.Should().NotBeNull("User creation should not fail");156 user.Id.Should().BeGreaterThan(0, "User should have valid ID");157 user.Email.Should().NotBeNullOrEmpty("Email is required");158}159```text160161---162163## Common Scenarios and Solutions164165| Scenario | Key Technique |166|------|----------|167| API response validation | `BeEquivalentTo()` + `Including()` selective comparison |168| Database entity validation | `BeEquivalentTo()` + `Excluding()` exclude auto-generated fields |169| Event validation | Subscribe to capture events then validate properties one by one |170171> Full code examples please refer to [references/common-scenarios.md](references/common-scenarios.md)172173---174175## Troubleshooting176177### Problem 1: BeEquivalentTo fails but objects look the same178179**Reason**: May contain auto-generated fields or timestamps180181**Solution**:182183```csharp184// Exclude dynamic fields185actual.Should().BeEquivalentTo(expected, options => options186 .Excluding(x => x.Id)187 .Excluding(x => x.CreatedAt)188 .Excluding(x => x.UpdatedAt)189);190```text191192### Problem 2: Collection order different causes failure193194**Reason**: Collection order is different195196**Solution**:197198```csharp199// Use BeEquivalentTo ignore order200actual.Should().BeEquivalentTo(expected); // Does not check order201202// Or explicitly specify need to check order203actual.Should().Equal(expected); // Checks order204```text205206### Problem 3: Floating point comparison fails207208**Reason**: Floating point precision issues209210**Solution**:211212```csharp213// Use precision tolerance214actualValue.Should().BeApproximately(expectedValue, 0.001);215```text216217---218219## When to Use This Skill220221### Applicable Scenarios222223Write unit tests or integration tests224Need to validate complex object structures225Compare API responses or database entities226Need clear failure messages227Establish domain-specific testing standards228229### Not Applicable Scenarios230231Performance testing (use dedicated benchmarking tools)232Load testing (use K6, JMeter, etc.)233UI testing (use Playwright, Selenium)234235---236237## Integration with Other Skills238239### Integration with unit-test-fundamentals240241First use `unit-test-fundamentals` to establish test structure, then use this skill to write assertions:242243```csharp244[Fact]245public void Calculator_Add_TwoPositiveNumbers_ShouldReturnSum()246{247 // Arrange - follow 3A Pattern248 var calculator = new Calculator();249250 // Act251 var result = calculator.Add(2, 3);252253 // Assert - use AwesomeAssertions254 result.Should().Be(5);255}256```text257258### Integration with test-naming-conventions259260Use `test-naming-conventions` naming conventions, combined with this skill's assertions:261262```csharp263[Fact]264public void CreateUser_WithValidData_ShouldReturnEnabledUser()265{266 var user = userService.CreateUser("test@example.com");267268 user.Should().NotBeNull()269 .And.BeOfType<User>();270 user.IsActive.Should().BeTrue();271}272```text273274### Integration with xunit-project-setup275276Install and use AwesomeAssertions in projects created with `xunit-project-setup`.277278---279280## Reference Resources281282### Original Articles283284This skill content is extracted from "Old School Software Engineer's Testing Practice - 30 Day Challenge" series:285286- **Day 04 - AwesomeAssertions Basic Application and Practical Techniques**287 - Ironman Article: https://ithelp.ithome.com.tw/articles/10374188288 - Sample Code: https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day04289290- **Day 05 - AwesomeAssertions Advanced Techniques and Complex Scenario Applications**291 - Ironman Article: https://ithelp.ithome.com.tw/articles/10374425292 - Sample Code: https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day05293294### Official Resources295296- **AwesomeAssertions GitHub**: https://github.com/AwesomeAssertions/AwesomeAssertions297- **AwesomeAssertions Official Documentation**: https://awesomeassertions.org/298299### Related Articles300301- **Fluent Assertions License Change Discussion**: https://www.dotblogs.com.tw/mrkt/2025/04/19/152408302303---304305## Summary306307AwesomeAssertions provides powerful and readable assertion syntax, an important tool for writing high-quality tests. Through:3083091. **Fluent Syntax**: Makes test code more readable3102. **Rich Assertions**: Covers various data types3113. **Custom Extensions**: Establish domain-specific assertions3124. **Performance Optimization**: Handle large data scenarios3135. **Completely Free**: Apache 2.0 license with no commercial restrictions314315Remember: Good assertions not only validate results but clearly express expected behavior and provide useful diagnostic information when failing.316317Refer to [templates/assertion-examples.cs](templates/assertion-examples.cs) for more practical examples.318````