From 3de91710252584eb550a970bcc4a3f67a8a66ce8 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Thu, 14 May 2026 11:19:46 +0100 Subject: [PATCH 1/2] test(assertions): harden WaitsFor timeout test --- .../WaitsForAssertionTests.cs | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/TUnit.Assertions.Tests/WaitsForAssertionTests.cs b/TUnit.Assertions.Tests/WaitsForAssertionTests.cs index 4c0c3e51f2..2b3133d604 100644 --- a/TUnit.Assertions.Tests/WaitsForAssertionTests.cs +++ b/TUnit.Assertions.Tests/WaitsForAssertionTests.cs @@ -44,25 +44,28 @@ await Assert.That(getValue).WaitsFor( [Test] public async Task WaitsFor_Fails_When_Timeout_Expires() { - var stopwatch = Stopwatch.StartNew(); - var value = 1; + var timeout = TimeSpan.FromMilliseconds(250); + var pollingInterval = TimeSpan.FromMilliseconds(10); + var attempts = 0; + Func getValue = () => + { + Interlocked.Increment(ref attempts); + return 1; + }; var exception = await Assert.That( - async () => await Assert.That(value).WaitsFor( + async () => await Assert.That(getValue).WaitsFor( assert => assert.IsEqualTo(999), - timeout: TimeSpan.FromMilliseconds(100), - pollingInterval: TimeSpan.FromMilliseconds(10)) + timeout: timeout, + pollingInterval: pollingInterval) ).Throws(); - stopwatch.Stop(); - - // Lower bound proves the timeout actually fired at the right moment. An upper bound - // here is a flake magnet — slow CI workers can spend >1s in exception construction - // and assertion-machinery cost after the timeout fires correctly. - await Assert.That(stopwatch.Elapsed).IsGreaterThanOrEqualTo(TimeSpan.FromMilliseconds(100)); + // Prove WaitsFor polled instead of failing immediately without asserting + // an exact wall-clock boundary, which varies by OS timer resolution. + await Assert.That(attempts).IsGreaterThan(1); // Verify error message contains useful information - await Assert.That(exception.Message).Contains("assertion did not pass within 100ms"); + await Assert.That(exception.Message).Contains($"assertion did not pass within {timeout.TotalMilliseconds:F0}ms"); await Assert.That(exception.Message).Contains("Last error:"); } From 019c329b8dda191103e7530eeeafa9ebef85fb18 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Thu, 14 May 2026 11:36:00 +0100 Subject: [PATCH 2/2] test(assertions): avoid WaitsFor retry timing --- TUnit.Assertions.Tests/WaitsForAssertionTests.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/TUnit.Assertions.Tests/WaitsForAssertionTests.cs b/TUnit.Assertions.Tests/WaitsForAssertionTests.cs index 2b3133d604..9ff2ed7e80 100644 --- a/TUnit.Assertions.Tests/WaitsForAssertionTests.cs +++ b/TUnit.Assertions.Tests/WaitsForAssertionTests.cs @@ -46,24 +46,15 @@ public async Task WaitsFor_Fails_When_Timeout_Expires() { var timeout = TimeSpan.FromMilliseconds(250); var pollingInterval = TimeSpan.FromMilliseconds(10); - var attempts = 0; - Func getValue = () => - { - Interlocked.Increment(ref attempts); - return 1; - }; + var value = 1; var exception = await Assert.That( - async () => await Assert.That(getValue).WaitsFor( + async () => await Assert.That(value).WaitsFor( assert => assert.IsEqualTo(999), timeout: timeout, pollingInterval: pollingInterval) ).Throws(); - // Prove WaitsFor polled instead of failing immediately without asserting - // an exact wall-clock boundary, which varies by OS timer resolution. - await Assert.That(attempts).IsGreaterThan(1); - // Verify error message contains useful information await Assert.That(exception.Message).Contains($"assertion did not pass within {timeout.TotalMilliseconds:F0}ms"); await Assert.That(exception.Message).Contains("Last error:");