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-guide-33description: 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 syntax4---5Source: kevintsengtw/dotnet-testing-agent-skills (MIT). Ported into dotnet-agent-harness.67# AwesomeAssertions Fluent Assertion Guide89This skill provides a complete guide for writing high-quality test assertions using AwesomeAssertions, covering basic10syntax, advanced techniques, and best practices.1112## Applicable Scenarios1314Use this skill when asked to perform the following tasks:1516- Write clear, highly readable test assertions17- Compare complex objects or collection contents18- Verify exception throwing and messages19- Use fluent syntax (Should/Be/Contain) for test validation20- Replace native Assert with AwesomeAssertions2122## About AwesomeAssertions2324**AwesomeAssertions** is a community fork version of FluentAssertions, using **Apache 2.0** license, completely free25with no commercial usage restrictions.2627### Core Features2829- Fully Free: Apache 2.0 license, suitable for commercial projects30- Fluent Syntax: Supports natural language style method chaining31- Rich Assertions: Covers objects, collections, strings, numbers, exceptions, and various other types32- Excellent Error Messages: Provides detailed and easy-to-understand failure information33- High Performance: Optimized implementation ensures test execution efficiency34- Extensible: Supports custom Assertion methods3536### Relationship with FluentAssertions3738AwesomeAssertions is a community fork of FluentAssertions, main differences:3940| Item | FluentAssertions | AwesomeAssertions |41| --------------------- | ----------------------------------- | ---------------------------- |42| **License** | Commercial projects require payment | Apache 2.0 (completely free) |43| **Namespace** | `FluentAssertions` | `AwesomeAssertions` |44| **API Compatibility** | Original | Highly compatible |45| **Community Support** | Official maintenance | Community maintenance |4647---4849## Installation and Setup5051### NuGet Package Installation5253````bash54# .NET CLI55dotnet add package AwesomeAssertions5657# Package Manager Console58Install-Package AwesomeAssertions59```text6061### csproj Setup (Recommended)6263```xml64<ItemGroup>65 <PackageReference Include="AwesomeAssertions" Version="9.1.0" PrivateAssets="all" />66</ItemGroup>67```text6869### Namespace Import7071```csharp72using AwesomeAssertions;73using Xunit;74```text7576---7778## Core Assertions Syntax7980All Assertions start with `.Should()`, combined with fluent method chaining.8182| Category | Common Methods | Description |83|------|----------|------|84| **Object** | `NotBeNull()`, `BeOfType<T>()`, `BeEquivalentTo()` | Null, type, equality checks |85| **String** | `Contain()`, `StartWith()`, `MatchRegex()`, `BeEquivalentTo()` | Content, patterns, case-insensitive comparison |86| **Number** | `BeGreaterThan()`, `BeInRange()`, `BeApproximately()` | Comparison, range, floating point precision |87| **Collection** | `HaveCount()`, `Contain()`, `BeEquivalentTo()`, `AllSatisfy()` | Count, content, order, conditions |88| **Exception** | `Throw<T>()`, `NotThrow()`, `WithMessage()`, `WithInnerException()` | Exception types, messages, nested exceptions |89| **Async** | `ThrowAsync<T>()`, `CompleteWithinAsync()` | Async exceptions and completion validation |9091> Full syntax examples and code please refer to [references/core-assertions-syntax.md](references/core-assertions-syntax.md)9293---9495## Advanced Techniques: Complex Object Comparison9697Use `BeEquivalentTo()` with `options` for deep object comparison:9899- **Exclude properties**: `options.Excluding(u => u.Id)` — exclude auto-generated fields100- **Dynamic exclusion**: `options.Excluding(ctx => ctx.Path.EndsWith("At"))` — exclude by pattern101- **Circular references**: `options.IgnoringCyclicReferences().WithMaxRecursionDepth(10)`102103---104105## Advanced Techniques: Custom Assertions Extension106107Create domain-specific extension methods, like `product.Should().BeValidProduct()`, and reusable exclusion extensions like `ExcludingAuditFields()`.108109Refer to [templates/custom-assertions-template.cs](templates/custom-assertions-template.cs) for complete implementation.110111> Full examples please refer to [references/complex-object-assertions.md](references/complex-object-assertions.md)112113---114115## Performance Optimization Strategies116117- **Large data**: First use `HaveCount()` for quick count check, then sample validation (avoid full `BeEquivalentTo`)118- **Selective comparison**: Use anonymous objects + `ExcludingMissingMembers()` to only validate key properties119120```csharp121// Selective property comparison — only validate key fields122order.Should().BeEquivalentTo(new123{124 CustomerId = 123,125 TotalAmount = 999.99m,126 Status = "Pending"127}, options => options.ExcludingMissingMembers());128```text129130---131132## Best Practices and Team Standards133134### Test Naming Conventions135136Follow `Method_Scenario_ExpectedResult` pattern (e.g., `CreateUser_WithValidEmail_ShouldReturnEnabledUser`).137138### Error Message Optimization139140Add `because` string in assertions to provide clear failure context:141142```csharp143result.IsSuccess.Should().BeFalse("because negative payment amounts are not allowed");144```text145146### AssertionScope Usage147148Use `AssertionScope` to collect multiple failure messages, display all problems at once:149150```csharp151using (new AssertionScope())152{153 user.Should().NotBeNull("User creation should not fail");154 user.Id.Should().BeGreaterThan(0, "User should have valid ID");155 user.Email.Should().NotBeNullOrEmpty("Email is required");156}157```text158159---160161## Common Scenarios and Solutions162163| Scenario | Key Technique |164|------|----------|165| API response validation | `BeEquivalentTo()` + `Including()` selective comparison |166| Database entity validation | `BeEquivalentTo()` + `Excluding()` exclude auto-generated fields |167| Event validation | Subscribe to capture events then validate properties one by one |168169> Full code examples please refer to [references/common-scenarios.md](references/common-scenarios.md)170171---172173## Troubleshooting174175### Problem 1: BeEquivalentTo fails but objects look the same176177**Reason**: May contain auto-generated fields or timestamps178179**Solution**:180181```csharp182// Exclude dynamic fields183actual.Should().BeEquivalentTo(expected, options => options184 .Excluding(x => x.Id)185 .Excluding(x => x.CreatedAt)186 .Excluding(x => x.UpdatedAt)187);188```text189190### Problem 2: Collection order different causes failure191192**Reason**: Collection order is different193194**Solution**:195196```csharp197// Use BeEquivalentTo ignore order198actual.Should().BeEquivalentTo(expected); // Does not check order199200// Or explicitly specify need to check order201actual.Should().Equal(expected); // Checks order202```text203204### Problem 3: Floating point comparison fails205206**Reason**: Floating point precision issues207208**Solution**:209210```csharp211// Use precision tolerance212actualValue.Should().BeApproximately(expectedValue, 0.001);213```text214215---216217## When to Use This Skill218219### Applicable Scenarios220221Write unit tests or integration tests222Need to validate complex object structures223Compare API responses or database entities224Need clear failure messages225Establish domain-specific testing standards226227### Not Applicable Scenarios228229Performance testing (use dedicated benchmarking tools)230Load testing (use K6, JMeter, etc.)231UI testing (use Playwright, Selenium)232233---234235## Integration with Other Skills236237### Integration with unit-test-fundamentals238239First use `unit-test-fundamentals` to establish test structure, then use this skill to write assertions:240241```csharp242[Fact]243public void Calculator_Add_TwoPositiveNumbers_ShouldReturnSum()244{245 // Arrange - follow 3A Pattern246 var calculator = new Calculator();247248 // Act249 var result = calculator.Add(2, 3);250251 // Assert - use AwesomeAssertions252 result.Should().Be(5);253}254```text255256### Integration with test-naming-conventions257258Use `test-naming-conventions` naming conventions, combined with this skill's assertions:259260```csharp261[Fact]262public void CreateUser_WithValidData_ShouldReturnEnabledUser()263{264 var user = userService.CreateUser("test@example.com");265266 user.Should().NotBeNull()267 .And.BeOfType<User>();268 user.IsActive.Should().BeTrue();269}270```text271272### Integration with xunit-project-setup273274Install and use AwesomeAssertions in projects created with `xunit-project-setup`.275276---277278## Reference Resources279280### Original Articles281282This skill content is extracted from "Old School Software Engineer's Testing Practice - 30 Day Challenge" series:283284- **Day 04 - AwesomeAssertions Basic Application and Practical Techniques**285 - Ironman Article: https://ithelp.ithome.com.tw/articles/10374188286 - Sample Code: https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day04287288- **Day 05 - AwesomeAssertions Advanced Techniques and Complex Scenario Applications**289 - Ironman Article: https://ithelp.ithome.com.tw/articles/10374425290 - Sample Code: https://github.com/kevintsengtw/30Days_in_Testing_Samples/tree/main/day05291292### Official Resources293294- **AwesomeAssertions GitHub**: https://github.com/AwesomeAssertions/AwesomeAssertions295- **AwesomeAssertions Official Documentation**: https://awesomeassertions.org/296297### Related Articles298299- **Fluent Assertions License Change Discussion**: https://www.dotblogs.com.tw/mrkt/2025/04/19/152408300301---302303## Summary304305AwesomeAssertions provides powerful and readable assertion syntax, an important tool for writing high-quality tests. Through:3063071. **Fluent Syntax**: Makes test code more readable3082. **Rich Assertions**: Covers various data types3093. **Custom Extensions**: Establish domain-specific assertions3104. **Performance Optimization**: Handle large data scenarios3115. **Completely Free**: Apache 2.0 license with no commercial restrictions312313Remember: Good assertions not only validate results but clearly express expected behavior and provide useful diagnostic information when failing.314315Refer to [templates/assertion-examples.cs](templates/assertion-examples.cs) for more practical examples.316````