Eugene
Eugene

Reputation: 1093

Testing for exceptions in async methods

I'm a bit stuck with this code (this is a sample):

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

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

The code doesn't catch the exception, and fails with

Expected a System.Exception to be thrown, but no exception was thrown.

I'm sure I'm missing something, but docs seem to suggest this is the way to go. Some help would be appreciated.

Upvotes: 97

Views: 45703

Answers (5)

Marcin Sulecki
Marcin Sulecki

Reputation: 174

With Fluent Assertions v6.9 you can use short form:

var act = () => Fail();
act.Should().ThrowAsync<Exception>();

Upvotes: 3

enzo-ae
enzo-ae

Reputation: 41

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>();
}

Upvotes: 4

Bronek
Bronek

Reputation: 11245

Other variation of usage ThrowAsync method:

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

Upvotes: 5

gatsby
gatsby

Reputation: 1229

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.

Upvotes: 49

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236318

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.

Upvotes: 141

Related Questions