【问题标题】:How to handle exceptions thrown by Tasks in xUnit .net's Assert.Throws<T>?如何处理 xUnit .net 的 Assert.Throws<T> 中的 Tasks 抛出的异常?
【发布时间】:2012-12-14 15:05:15
【问题描述】:

以下异步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
}

为什么带有lambda 标记为async 修饰符的Assert.Throws&lt;T&gt; 会失败?

【问题讨论】:

  • 这是一个已知问题:xunit.codeplex.com/workitem/9799
  • +1 它似乎已在快照03e3be9a6781 中修复,该快照位于与发布2.0.0-alpha 关联的快照16883cb2351f 之前。但是使用 NuGet 包管理器更新解决方案后它仍然无法正常工作。

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


【解决方案1】:

更新

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


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

在这种情况下,async 委托正在返回 TaskTask&lt;T&gt;,并且 ArgumentNullException 不会直接从委托中抛出;相反,它被放置在Task (Task.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 中使用了类似的方法。

【讨论】:

  • 我稍微修改了您的代码,因为我相信只有“ArgumentNullException”才能达到Assert。可能值得考虑的另一件事是原始Assert.Throws 返回异常(例如,您也可以测试异常消息)。
【解决方案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;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-22
    • 2013-03-05
    • 1970-01-01
    • 2019-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多