简体   繁体   中英

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("notarealuser@example.com", 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?

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

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

Example:

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

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

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("notarealuser@example.com", testpassword));         
}
catch (HttpResponseException ex)
{
    expectedException = ex;
}

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

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

You could try using something like this:

 try
 {
     await client.LoginAsync("notarealuser@example.com", testpassword);
 }
 catch (Exception ex)
 {
     Assert.That(ex, Is.InstanceOf(typeof (HttpResponseException)));
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM