NUnit3: Assert.Throws с асинхронной задачей

Я пытаюсь перенести тест на NUnit3 и получаю System.ArgumentException: методы async void не поддерживаются, вместо этого используйте "async Task".

[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, похоже, принимает TestDelegate, определяемый как:

public delegate void TestDelegate();

следовательно, исключение ArgumentException. Каков наилучший способ для переноса этого кода?

Ответы

Ответ 1

Это было разрешено Нунитом. Теперь вы можете использовать Assert.ThrowsAsync < > ()

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

Пример:

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

Ответ 2

Я бы рекомендовал следующий код вместо Assert.ThrowsAsync, так как это более читабельно:

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

Ответ 3

Чтобы исключение было выбрано, лучше не утверждать в блоке catch, если вы так решите его использовать. Таким образом, вы можете быть уверены, что вы выбрали правильный тип исключения, потому что иначе вы получите нулевую ссылку или неотобравшееся другое исключение.

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

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

Ответ 4

В итоге я написал статическую функцию, которая отражает то, что делает NUnit. Был целый разговор в https://github.com/nunit/nunit/issues/464 об этом.

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

Затем из моих тестов я могу использовать его, например

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

Ответ 5

Вы можете попробовать использовать что-то вроде этого:

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