Consider this unit test of an API client with an async function Index. Index should throw an exception when an http error occurs and thats what I want to test.
public async Task TestServiceError()
{
var client = GetMockClient("{RETURN}", System.Net.HttpStatusCode.BadRequest);
await Should.ThrowAsync<PreorderException>(async () => await client.Index());
}
Index() is implemented like:
public async Task<string> Index()
{
var response = await Client.GetAsync($"{Ingress}/");
if (!response.IsSuccessStatusCode)
throw new PreorderException(response.StatusCode, response.ReasonPhrase);
var received = await response.Content.ReadAsStreamAsync();
var readStream = new StreamReader(received, Encoding.UTF8);
return readStream.ReadToEnd();
}
So it throws a PreorderException on an error http statuscode after GetAsync os awaited.
I'm left wondering what the difference would be by not using async.
public void TestServiceError()
{
var client = GetMockClient("{RETURN}", System.Net.HttpStatusCode.BadRequest);
Should.Throw<PreorderException>(async () => await client.Index());
}
or
public Task TestServiceError()
{
var client = GetMockClient("{RETURN}", System.Net.HttpStatusCode.BadRequest);
await Should.ThrowAsync<PreorderException>(() => client.Index());
}
Maybe this is the best even? As there is a Task returned from Index and the await in front of Should await that Task?
The non-async version looks less bulky, and I don't see a reason why it would not work. Throw is synchronous and the await is done in the delegate argument. Plus it's just a unit test with short live code called once.
(The real code has 20 of these so then it makes more sense to remove all the awaits)
await Should.ThrowAsync<PreorderException>(async () => await client.Index());
await Should.ThrowAsync<PreorderException>(async () => await client.FindByODLTest("order", "dealer", "lab"));
await Should.ThrowAsync<PreorderException>(async () => await client.RegisterAsync(new()));
// etc.
Shouldclass. I suspectShoudlyin which caseShould.Throwis async-ready and blocks on the task. That's a very unusual API but probably exists to stop people from accidentally callingasync void. That's a very strong hint why you shouldn't useShoult.Throw(Func<Task>)- it's unclear what's going on. The method is there to stop you from shooting your own foot