h bob h bob - 3 months ago 18
C# Question

Asserting exceptions in async delegates

I'm using NUnit 3. I wrote an extension method:

public static T ShouldThrow<T>(this TestDelegate del) where T : Exception {
return Assert.Throws(typeof(T), del) as T;
}


Which allows me to do this:

TestDelegate del = () => foo.doSomething(null);
del.ShouldThrow<ArgumentNullException>();


Now I want something similar for async:

AsyncTestDelegate del = async () => await foo.doSomething(null);
del.ShouldThrowAsync<ArgumentNullException>();


So I wrote this:

public static async Task<T> ShouldThrowAsync<T>(this AsyncTestDelegate del) where T : Exception {
return (await Assert.ThrowsAsync(typeof(T), del)) as T;
}


But that doesn't work:
'Exception' does not contain a definition for 'GetAwaiter' and no extension method 'GetAwaiter' accepting a first argument of type 'Exception' could be found (are you missing a using directive or an assembly reference?)
.

What am I doing wrong?

Answer

As far as I can tell, Assert.ThrowsAsync doesn't return a Task, and cannot be awaited. Remove await from your extension method.

public static T ShouldThrowAsync<T>(this AsyncTestDelegate del) where T : Exception {
  return Assert.ThrowsAsync(typeof(T), del) as T;
}

Example usage from the docs. Note that Assert.ThrowsAsync returns a MyException and that the await is in the delegate.

[TestFixture]
public class UsingReturnValue
{
  [Test]
  public async Task TestException()
  {
    MyException ex = Assert.ThrowsAsync<MyException>(async () => await MethodThatThrows());

    Assert.That( ex.Message, Is.EqualTo( "message" ) );
    Assert.That( ex.MyParam, Is.EqualTo( 42 ) ); 
  }
}