NUnit3: Assert.Throws with async Task

C#AsynchronousNunitNunit 3.0

C# Problem Overview


I am trying to port a test to NUnit3 and am getting a System.ArgumentException : 'async void' methods are not supported, please use 'async Task' instead.

[Test]
public void InvalidUsername()
{
	...
	var exception = Assert.Throws<HttpResponseException>(async () => await client.LoginAsync("[email protected]", testpassword));
	exception.HttpResponseMessage.StatusCode.ShouldEqual(HttpStatusCode.BadRequest); // according to http://tools.ietf.org/html/rfc6749#section-5.2
	...
}

Assert.Throws appears to take a TestDelegate, defined as:

public delegate void TestDelegate();

hence the ArgumentException. What is the best way to port this code?

C# Solutions


Solution 1 - C#

This was resolved by Nunit. You can now use Assert.ThrowsAsync<>()

https://github.com/nunit/nunit/issues/1190

Example:

Assert.ThrowsAsync<Exception>(() => YourAsyncMethod());

Solution 2 - C#

I would recommend the following code instead of Assert.ThrowsAsync, as this is more readable:

// Option A
[Test]
public void YourAsyncMethod_Throws_YourException_A()
{
    // Act
    AsyncTestDelegate act = () => YourAsyncMethod();

    // Assert
    Assert.That(act, Throws.TypeOf<YourException>());
}

// Option B (local function)
[Test]
public void YourAsyncMethod_Throws_YourException_B()
{
    // Act
    Task Act() => YourAsyncMethod();

    // Assert
    Assert.That(Act, Throws.TypeOf<YourException>());
}

Solution 3 - C#

To ensure the exception was thrown, it's better to not assert in the catch block if you so choose to use one. This way, you can be sure the correct exception type is thrown because otherwise you'll get a null reference or an uncaught different exception.

HttpResponseException expectedException = null;
try
{
	await  client.LoginAsync("[email protected]", testpassword));         
}
catch (HttpResponseException ex)
{
	expectedException = ex;
}

Assert.AreEqual(HttpStatusCode.NoContent, expectedException.Response.BadRequest);

Solution 4 - C#

I ended up writing a static function that mirrors what NUnit does. There was a whole conversation at https://github.com/nunit/nunit/issues/464 about this.

public static async Task<T> Throws<T>(Func<Task> code) where T : Exception
{
    var actual = default(T);

    try
    {
        await code();
        Assert.Fail($"Expected exception of type: {typeof (T)}");
    }
    catch (T rex)
    {
        actual = rex;
    }
    catch (Exception ex)
    {
        Assert.Fail($"Expected exception of type: {typeof(T)} but was {ex.GetType()} instead");
    }

    return actual;
}

Then from my tests I can use it such as

var ex = await CustomAsserts.Throws<HttpResponseException>(async () => await client.DoThings());
Assert.IsTrue(ex.Response.StatusCode == HttpStatusCode.BadRequest);

Solution 5 - C#

You could try using something like this:

 try
 {
     await client.LoginAsync("[email protected]", testpassword);
 }
 catch (Exception ex)
 {
     Assert.That(ex, Is.InstanceOf(typeof (HttpResponseException)));
 }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiontikinoaView Question on Stackoverflow
Solution 1 - C#ZabbuView Answer on Stackoverflow
Solution 2 - C#arniView Answer on Stackoverflow
Solution 3 - C#BrianPMorinView Answer on Stackoverflow
Solution 4 - C#EricView Answer on Stackoverflow
Solution 5 - C#woitheqView Answer on Stackoverflow