如何在xUnit .net的Assert.Throws <T>中处理由Tasks抛出的异常?

Nik*_*nis 19 c# xunit.net async-await c#-5.0

通过报告没有抛出异常,以下带有修饰符标记的异步xUnit.net测试失败:lambdaasync

    [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
    }
Run Code Online (Sandbox Code Playgroud)

为了确保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
}
Run Code Online (Sandbox Code Playgroud)

为什么Assert.Throws<T>带有修饰符的lambda标记async失败?

Ste*_*ary 36

更新

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


我怀疑这Assert.Throws不是 - 意识到async.我建议在xUnit团队中提出这个问题,建议ThrowsAsync添加一个.

一个async在此情况下委托返回TaskTask<T>,并且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);
}
Run Code Online (Sandbox Code Playgroud)

可以这样使用:

[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
}
Run Code Online (Sandbox Code Playgroud)

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