How to stop forgetting to await an awaitable call
Now that all those .NET code bases start to get littered with async
and await
statements, I’m observing another phenomenon: forgetting to await
an awaitable member. Not just in the code I deal with in my day job, but a lot of users of Fluent Assertions have been running into this, especially since we introduced “async” versions such as ThrowAsync
and NotThrowAsync
. You would expect that modern IDEs have become smart enough to help us with that. And indeed, both Visual Studio and Rider do, but only to an extend.
Consider for example the following (contrived) async method:
public class Class
{
public async Task AsyncMethod()
{
await Task.Run(() =>
{
throw new InvalidOperationException();
});
}
}
If you would call this AsyncMethod
without using the await
keyword, like this…
Class subjectUnderTest = new();
subjectUnderTest.AsyncMethod();
…no exception will be thrown. But fortunately, the compiler will issue warning CS1998
:
This async method lacks ‘await’ operators and will run synchronously. Consider using the ‘await’ operator to await non-blocking API calls, or ‘await Task.Run(…)’ to do CPU-bound work on a background thread.
So if you’re like me and always treat warnings as errors, you’ll be fine.
Now consider a unit test that uses Fluent Assertions to assert that the right type exception is thrown: