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:

--

--

Dennis "The Continuous Improver" Doomen

Dennis is a veteran architect in the .NET space with a special interest in writing clean code, Domain Driven Design, Event Sourcing and everything agile.