I need to assert that the initial synchronous part of an async method executes within a certain duration. Is this possible with fluent assertions? I also need to assert the minimum and maximum total duration (eg, using CompleteWithinAsync
and NotCompleteWithinAsync
), so the solution needs to cover all three timings (see my other question How do I assert that an async task should complete within a minimum and maximum time?) on a single task call/await expression.
Asked
Active
Viewed 80 times
0

tg73
- 415
- 3
- 10
-
Without knowing those specified methods, I would try to get a DateTime.Now, before then define a TimeSpan and assert that the difference is between those two. Would this work? – Jazz. Feb 16 '23 at 13:54
-
The initial synchronous part will be over when the method returns the `Task`, so just you https://fluentassertions.com/executiontime without awaiting. However, without mocking the behavior of the `TaskScheduler` you may get some variability. – Jodrell Feb 16 '23 at 13:55
-
Just curious: what would that tell you, exactly? It may depend on the machine and its load at the time if that test would fail or succeed. – Fildor Feb 16 '23 at 14:01
-
3@Fildor, its a kind of test that would likely lead to intermittent failure in a CI/CD pipeline. – Jodrell Feb 16 '23 at 14:02
-
@Jodrell Can you provide an example that asserts all three timing constrains on one async task invocation? It's combining these things together which is problematic. I'll edit the question to make this clearer. – tg73 Feb 16 '23 at 14:03
-
@tg73, if you can provide a compiling, executing example, I, or another may be able to help. – Jodrell Feb 16 '23 at 14:05
-
1@Fildor The tests cover some complex async caching logic. When testing, dummy "work" is used with controlled duration, and the asserts have wide margins. It's imperfect, but necessary, and worst case the tests will be explicit (ie, not run in CI/DI). – tg73 Feb 16 '23 at 14:10
1 Answers
2
The trivial and contrived, seems to function as expected.
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
public class Program
{
public static async Task Main()
{
// Arrange
static async Task someAsyncBehaviourMock()
{
await Task.Yield();
await Task.Delay(1000);
};
var s1 = Stopwatch.StartNew();
var s2 = Stopwatch.StartNew();
// Act
var task = Target(someAsyncBehaviourMock);
s1.Stop();
await task;
s2.Stop();
// Assert
s1.ElapsedMilliseconds.Should().BeGreaterThan(1000).And.BeLessThan(2000);
s2.ElapsedMilliseconds.Should().BeGreaterThan(2000).And.BeLessThan(3000);
Console.WriteLine(
$"Success. s1:{s1.ElapsedMilliseconds}, s2:{s2.ElapsedMilliseconds}");
}
private static async Task Target(Func<Task> someAsyncBehaviour)
{
// Initial Sync Behaviour
Thread.Sleep(1000);
// Injected Async Behaviour
await someAsyncBehaviour();
}
}

Jodrell
- 34,946
- 5
- 87
- 124
-
thanks for your solution. I have gone with something like this for now, but I was hoping that there would be native support for these kind of timings and assertions in the fluent assertions API. As illustrated by your solution., it's a lot of ceremony for something which could be one concise fluent expression if support was added. I'll log a suggestion on the FA github. – tg73 Feb 16 '23 at 16:52