A forgotten await on Assert.ThrowsAsync means the test always passes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // ====================================================================== // Q: How do you test async code and exceptions? // // - A forgotten await on Assert.ThrowsAsync means the test always passes. The // xUnit analyzer catches it (keep the analyzers enabled). // - Never use .Result / .Wait() in tests: deadlocks and hidden // AggregateExceptions. // ====================================================================== [Fact] public async Task Place_without_stock_throws() // async Task, never async void { stock.TryReserveAsync("LIM-001", 5, Arg.Any<CancellationToken>()).Returns(false); var ex = await Assert.ThrowsAsync<DomainException>( () => handler.Handle(new PlaceOrder(orderId), CancellationToken.None)); Assert.Contains("Insufficient stock", ex.Message); } // Synchronous: Assert.Throws<T> (exact type) or Assert.ThrowsAny<T> (subclasses too) Assert.Throws<ArgumentException>(() => new Money(10m, "euro")); |