Async Constraint Support
NUnit constraints fully support testing asynchronous code. This page covers patterns for using constraints with async methods, tasks, and delegates.
Testing Async Methods
Basic Async Assertions
Use async lambdas with Assert.That to test async code:
// Test async method return values
Assert.That(async () => await service.GetValueAsync(), Is.EqualTo(42));
// Test that async method completes without throwing
Assert.That(async () => await service.InitializeAsync(), Throws.Nothing);
// Test async exception throwing
Assert.That(async () => await service.InvalidOperationAsync(),
Throws.TypeOf<InvalidOperationException>());
Testing Task Results
You can also await tasks directly before asserting:
// Await first, then assert
var result = await calculator.AddAsync(2, 3);
Assert.That(result, Is.EqualTo(5));
// Or use Assert.ThatAsync (NUnit 4.0+)
await Assert.ThatAsync(async () => await calculator.AddAsync(2, 3), Is.EqualTo(5));
Exception Testing with Async Code
ThrowsConstraint with Async
// Test for specific exception type
Assert.That(async () => await service.FailingMethodAsync(),
Throws.TypeOf<InvalidOperationException>());
// Test exception message
Assert.That(async () => await service.FailingMethodAsync(),
Throws.TypeOf<InvalidOperationException>()
.With.Message.Contains("expected error"));
// Test inner exception
Assert.That(async () => await service.FailingMethodAsync(),
Throws.TypeOf<AggregateException>()
.With.InnerException.TypeOf<TimeoutException>());
ThrowsNothing with Async
// Verify async method completes successfully
Assert.That(async () => await service.SafeMethodAsync(), Throws.Nothing);
Delayed Constraints with Async
Use DelayedConstraint for testing eventually-consistent async operations:
// Poll until condition is true (or timeout)
Assert.That(async () => await service.IsReadyAsync(),
Is.True.After(5).Seconds.PollEvery(100).MilliSeconds);
// Wait for value to appear
Assert.That(async () => await cache.GetCountAsync(),
Is.GreaterThan(0).After(2000, 100));
Collection Constraints with Async Enumerables
For IAsyncEnumerable<T>, materialize the collection first:
// Convert to list first
var items = await asyncEnumerable.ToListAsync();
Assert.That(items, Has.Count.EqualTo(5));
Assert.That(items, Is.All.Positive);
// Or use helper method
Assert.That(await ToListAsync(service.GetItemsAsync()), Has.Some.GreaterThan(100));
Best Practices
Use async lambdas when testing methods that return
TaskorTask<T>:Assert.That(async () => await method(), constraint);Avoid blocking calls like
.Resultor.Wait()- they can cause deadlocks:// BAD - can deadlock Assert.That(service.GetValueAsync().Result, Is.EqualTo(42)); // GOOD - use async lambda Assert.That(async () => await service.GetValueAsync(), Is.EqualTo(42));Use
Throws.Nothingto explicitly verify async code doesn't throw:Assert.That(async () => await service.ProcessAsync(), Throws.Nothing);Use
DelayedConstraintfor eventually-consistent operations instead ofTask.Delay:// BAD - arbitrary wait await Task.Delay(1000); Assert.That(value, Is.True); // GOOD - polls until true or timeout Assert.That(() => value, Is.True.After(2).Seconds.PollEvery(100).MilliSeconds);
See Also
- Throws Constraint - Exception testing
- ThrowsNothing Constraint - Verify no exception
- Delayed Constraint - Polling and timeouts