在异步方法中测试异常

我对这段代码有点困惑(这是一个示例) :

public async Task Fail()
{
await Task.Run(() => { throw new Exception(); });
}


[Test]
public async Task TestFail()
{
Action a = async () => { await Fail(); };
a.ShouldThrow<Exception>();
}

代码没有捕获异常,并且失败

期望抛出 System.Exception,但没有抛出任何异常 抛出。

我肯定遗漏了什么但医生似乎认为这是唯一的办法。如果你能帮忙我会很感激的。

35356 次浏览

You should use Func<Task> instead of Action:

[Test]
public void TestFail()
{
Func<Task> f = async () => { await Fail(); };
f.ShouldThrow<Exception>();
}

That will call the following extension which is used to verify asynchronous methods

public static ExceptionAssertions<TException> ShouldThrow<TException>(
this Func<Task> asyncAction, string because = "", params object[] becauseArgs)
where TException : Exception

Internally this method will run task returned by Func and wait for it. Something like

try
{
Task.Run(asyncAction).Wait();
}
catch (Exception exception)
{
// get actual exception if it wrapped in AggregateException
}

Note that test itself is synchronous.

With Fluent Assertions v5+ the code will be like :

ISubject sut = BuildSut();
//Act and Assert
Func<Task> sutMethod = async () => { await sut.SutMethod("whatEverArgument"); };
await sutMethod.Should().ThrowAsync<Exception>();

This should work.

Other variation of usage ThrowAsync method:

await Should.ThrowAsync<Exception>(async () => await Fail());

With Fluent Assertions v5.7 they introduced the Awaiting overload so now you can do as following:

public async void TestFail()
{
await this.Awaiting(_ => Fail()).Should().ThrowAsync<Exception>();
}