aweXpect
aweXpect is a fluent assertion library for .NET. It turns test verifications into readable sentences and produces failure messages that explain in plain English what was expected and what actually happened.
await Expect.That(message).IsEqualTo("It's a compliment");
Expected that messageis equal to "It's a compliment",but it was "It's a complement" which differs at index 12:↓ (actual)"It's a complement""It's a compliment"↑ (expected)
Why aweXpect?
- Async-first
- Performant
- Extensible
- Any runner
Every expectation is awaited. The same fluent chain works for sync values, Task, IAsyncEnumerable, exceptions and HTTP responses - there is no parallel …Async() API to remember.
// Plain value
await Expect.That(result).IsEqualTo(42);
// Task<T>
await Expect.That(_users.GetAsync(id))
.Satisfies(u => u.IsActive);
// IAsyncEnumerable<T> - the cancellation token flows through the stream
await Expect.That(_orders.StreamAsync())
.Contains(o => o.IsPriority)
.WithCancellation(cancellationToken);
// Delegate that throws
await Expect.That(() => _payments.ChargeAsync(-1m))
.ThrowsExactly<ArgumentOutOfRangeException>();
Because the chain is awaited, Because(...) and WithCancellation(...) attach once at the end instead of being threaded through every method. Multiple expectations compose directly via Expect.ThatAll(...) - no thread-static assertion scope.
The happy path - passing assertions, the common case in a healthy test suite - is the path that has been optimised.
Comparing strings, ignoring case
See the benchmarks for the full set.
The aweXpect.Core package is intentionally kept stable so extensions don't fight over versions. Add expectations for any type with extension methods on IThat<TType>:
public static AndOrResult<string, IThat<string>> IsAbsolutePath(
this IThat<string> subject)
=> new(subject.Get().ExpectationBuilder.AddConstraint((it, grammars)
=> new IsAbsolutePathConstraint(it, grammars)),
subject);
// usage
await Expect.That("/var/log").IsAbsolutePath();
The full walkthrough is at Write your own extension.
[Fact] // xUnit
[Test] // NUnit / TUnit
[TestMethod] // MSTest
public async Task IsActive()
=> await Expect.That(user.IsActive).IsTrue();
xUnit (v2 and v3), NUnit (v3 and v4), MSTest and TUnit are detected automatically - failures throw the framework-native exception, so they integrate cleanly with each runner.
Migrating from another assertion library?
The aweXpect.Migration analyzer ships code-fix providers that rewrite most FluentAssertions and xunit.Assert call sites for you. See the migration guide for the full walkthrough.
Companion libraries
aweXpect ships a small core with focused extensions for common ecosystems:
- aweXpect.Json - expectations for
System.Text.Json. - aweXpect.Web - expectations for
HttpClientandHttpResponseMessage. - aweXpect.Reflection - expectations for reflection types.
- aweXpect.Testably - expectations for Testably.Abstractions file and time systems.
- aweXpect.Mockolate - expectations for Mockolate mock interactions.
Where to go next
- Getting Started - install the package and write your first expectation.
- Migration - automated code fixes for moving from FluentAssertions or
xunit.Assert. - Advanced - multiple expectations, cancellation, customization, and more.
- Write your own extension - add expectations for your own types using
aweXpect.Core.