【问题标题】:Testing for exceptions in async methods在异步方法中测试异常
【发布时间】:2018-12-31 17:29:01
【问题描述】:

我对这段代码有点困惑(这是一个示例):

public async Task Fail()
{
    await Task.Run(() => { throw new Exception(); });
}

[Test]
public async Task TestFail()
{
    Action a = async () => { await Fail(); };
    a.ShouldThrow<Exception>();
}

代码没有捕捉到异常,失败了

预计会抛出 System.Exception,但没有出现异常 扔了。

我确定我遗漏了一些东西,但文档似乎表明这是要走的路。一些帮助将不胜感激。

【问题讨论】:

  • 好的,谢谢。错过了。但不能解决问题。
  • 问题是什么?
  • @stuartd 实际上,不,在测试异步方法时需要异步。 ShouldThrow 不是异步的。这可能是一个原因吗?
  • 您的问题是Action - 这会创建一个async void 方法。正确的异步委托等价物是Func&lt;Task&gt;
  • Fail 没有理由调用Task.Run,它只会抛出异常,TestFail 没有理由有匿名方法,你可以使用Fail委托而不将其包装在另一个不做任何事情的方法调用中。

标签: c# async-await nunit fluent-assertions


【解决方案1】:

您应该使用Func&lt;Task&gt; 而不是Action

[Test]
public void TestFail()
{
    Func<Task> f = async () => { await Fail(); };
    f.ShouldThrow<Exception>();            
}

这将调用以下用于验证异步方法的扩展

public static ExceptionAssertions<TException> ShouldThrow<TException>(
    this Func<Task> asyncAction, string because = "", params object[] becauseArgs)
        where TException : Exception        

这个方法在内部会运行Func返回的任务并等待它。类似的东西

try
{
    Task.Run(asyncAction).Wait();
}
catch (Exception exception)
{
    // get actual exception if it wrapped in AggregateException
}

请注意,测试本身是同步的。

【讨论】:

  • 异步等待真的有必要吗?似乎只需 Func&lt;Task&gt; f = () =&gt; Fail(); 就可以正常工作
  • 如果您有兴趣在测试之前等待调用完成执行。
  • 仅供参考 - 在最新版本 (v5) 的 fluentassertions 中,语法为:f.Should().Throw
  • 如果ShouldThrow 方法等待生成的任务,那么在函数中等待它应该没有关系?
  • 不知道它是新的还是当时已经可用,但official website 表示也可以使用该操作。即使由于某种原因我无法让它工作。
【解决方案2】:

使用 Fluent Assertions v5+,代码将如下所示:

ISubject sut = BuildSut();
//Act and Assert
Func<Task> sutMethod = async () => { await sut.SutMethod("whatEverArgument"); };
await sutMethod.Should().ThrowAsync<Exception>();

这应该可行。

【讨论】:

  • 没有await缺失吗? await sutMethod.Should().ThrowAsync&lt;Exception&gt;();
  • 我认为在第三行,async-await 关键字对是不必要的,没有它也对我有用。
  • @Károly Ozsvárt :我认为它对您有用,因为您正在测试的代码没有等待在达到预期抛出之前需要继续的等待。这对于方法中的验证代码很常见(因为它通常首先出现)并且可能在测试中很常见,因为所有依赖项都可能被模拟以返回已完成的任务。但是,如果你打了一个延续,它就行不通了。
  • 同步版本sutMethod.Should().Throw&lt;Exception&gt;(); 也适用于我。我认为这只是阻塞,在我的测试中这是一个阻塞调用我很好。
  • 你如何测试消息?等待 sutMethod.Should().ThrowAsync().WithMessage("AlaMaKota"); ?
【解决方案3】:

使用 ThrowAsync 方法的其他变体:

await Should.ThrowAsync<Exception>(async () => await Fail());

【讨论】:

    猜你喜欢
    • 2017-08-05
    • 1970-01-01
    • 2013-06-28
    • 2018-04-09
    • 2021-06-14
    • 2012-10-01
    • 2013-03-16
    • 2011-11-07
    • 1970-01-01
    相关资源
    最近更新 更多