How can I unit test this async method which (correctly) throws an exception?
The problem is that your assertion framework does not understand asynchronous methods. I recommend you raise an issue with them.
In the meantime, you can use the source for Should.Throw
to write your own MyShould.ThrowAsync
:
public static async Task<TException> ThrowAsync<TException>(Func<Task> actual)
where TException : Exception
{
try
{
await actual();
}
catch (TException e)
{
return e;
}
catch (Exception e)
{
throw new ChuckedAWobbly(new ShouldlyMessage(typeof(TException), e.GetType()).ToString());
}
throw new ChuckedAWobbly(new ShouldlyMessage(typeof(TException)).ToString());
}
And use it as such:
var result = await MyShould.ThrowAsync<HttpRequestException>
(async () => await service.SearchAsync(searchOptions));
or the slightly simpler and equivalent:
var result = await MyShould.ThrowAsync<HttpRequestException>
(() => service.SearchAsync(searchOptions));
Unit testing async code/functionality is pretty hard. I myself am getting into unit testing async and running into the same problems as you do.
I found the following two resources very helpful:
- Best practices in async programming - it delves into the subject of async and the problems with testing it.
- Unit testing async the wrong way and Unit testing async the right way - delves into the subject, shows the problems that you will encounter and how to setup the testing.
Test it like this:
var result = Should.Throw<HttpRequestException>
(() => service.SearchAsync(searchOptions).Result);
Or:
var result = Should.Throw<HttpRequestException>
(() => service.SearchAsync(searchOptions).Wait());
Otherwise, your Should.Throw
returns before the async
lambda has completed.