如何处理xUnit .net中的Tasks抛出的异常Assert.Throws <t>?</t>

时间:2012-12-29 18:59:12

标签: c# async-await c#-5.0 xunit.net

以下异步xUnit.net测试标有lambda修饰符的async因报告没有引发异常而失败:

    [Theory, AutoWebData]
    public async Task SearchWithNullQueryThrows(
        SearchService sut,
        CancellationToken dummyToken)
    {
        // Fixture setup
        // Exercise system and verify outcome
        Assert.Throws<ArgumentNullException>(async () =>
            await sut.SearchAsync(null, dummyToken));
        // Teardown
    }

为了确保实际抛出ArgumentNullException,我明确使用了try-catch块。它工作正常,但结果代码不干净(与第一次测试相比):

[Theory, AutoWebData]
public async Task SearchWithNullQueryThrows(
    SearchService sut,
    CancellationToken dummyToken)
{
    // Fixture setup
    var expected = typeof(ArgumentNullException);
    Type actual = null;
    // Exercise system
    try
    {
        await sut.SearchAsync(null, dummyToken);
    }
    catch (ArgumentNullException e)
    {
        actual = e.GetType();
    }
    // Verify outcome
    Assert.Equal(expected, actual);
    // Teardown
}

为什么标有Assert.Throws<T>修饰符的lambda的{​​{1}}会失败?

2 个答案:

答案 0 :(得分:36)

<强>更新

这已在xUnit 2中解决,添加了Assert.ThrowsAsync


我怀疑Assert.Throws不是async - 知道。我建议向xUnit团队提出此问题,建议添加ThrowsAsync

在这种情况下,async委托正在返回TaskTask<T>,并且ArgumentNullException不会直接从委托中退出;相反,它放在TaskTask.Exception.InnerException)上。 Assert.Throws期望异常直接从委托中抛出,而不是放在返回值的属性上。

您可以创建自己的AssertEx.ThrowsAsync

public static async Task ThrowsAsync<TException>(Func<Task> func)
{
  var expected = typeof(TException);
  Type actual = null;
  try
  {
    await func();
  }
  catch (Exception e)
  {
    actual = e.GetType();
  }
  Assert.Equal(expected, actual);
}

可以这样使用:

[Theory, AutoWebData]
public async Task SearchWithNullQueryThrows(
    SearchService sut,
    CancellationToken dummyToken)
{
    // Fixture setup
    // Exercise system and verify outcome
    await AssertEx.ThrowsAsync<ArgumentNullException>(async () =>
        await sut.SearchAsync(null, dummyToken));
    // Teardown
}

我在MSTest中使用了类似的方法。

答案 1 :(得分:2)

如果您还需要返回异常以进行验证,那么这可能很有用:

public static async Task<Exception> AssertThrowsAsync<TException>(Func<Task> func)
    {
        var expected = typeof (TException);
        Exception exception = null;
        Type actual = null;
        try
        {
            await func();
        }
        catch (Exception e)
        {
            actual = e.GetType();
            exception = e;
        }
        Assert.NotNull(exception);
        Assert.Equal(expected, actual);
        return exception;
    }