tikinoa
tikinoa

Reputation: 1317

NUnit3: Assert.Throws with async Task

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?

Upvotes: 74

Views: 33018

Answers (5)

Zabbu
Zabbu

Reputation: 1477

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

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

Example:

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

Upvotes: 125

arni
arni

Reputation: 2407

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

Upvotes: 14

Eric
Eric

Reputation: 231

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

Upvotes: 1

BrianPMorin
BrianPMorin

Reputation: 67

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

Upvotes: 0

woitheq
woitheq

Reputation: 1

You could try using something like this:

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

Upvotes: -5

Related Questions