【问题标题】:How to use a breakpoint after await in unit test?如何在单元测试中等待后使用断点?
【发布时间】:2014-09-09 03:23:15
【问题描述】:

await 执行 async 方法后,我很惊讶我的断点在引用等待的 Task<T> 的行上从未被命中:

    [Test]
    public async void GetSomethingTest()
    {
        var service = SimpleIoc.Default.GetInstance<IService>();
        var result = await service.TryGetSomethingAsync(20);
        Assert.IsTrue(result.IsSuccess);
        Assert.IsNotNull(result.ReturnValue);
    }

在第一个Assert 行放置断点不会被命中,但测试通过。

await 返回时如何中断?

更新:我猜这是因为测试框架不是 awaiting 调用测试方法,我使用的是 NUnit 2.6.3 并声称支持 async,但是是否这需要在await 之后中断,就像我正在尝试做的那样,我不确定......

【问题讨论】:

  • 将测试方法从 async void 更改为 async Task
  • @Neel 没有帮助:(
  • 我在调试单元测试时遇到了各种各样的问题。如果它不能按照您想要的方式工作,请将您的测试复制到 ConsoleApplication 并在那里调试它们。这样麻烦少了很多。
  • 我每天都对 Visual Studio 和/或 NUnit 感到越来越沮丧。我无法在基于异步的测试中正确设置断点。我在这里遵循了所有建议的答案,但没有任何效果。目前在 NUnit 3.13.1 上可能会回到 Java、NodeJS 和 Python。我从来没有遇到过这些意想不到的、无法接受的愚蠢问题。

标签: c# nunit async-await .net-4.5 c#-5.0


【解决方案1】:

问题是你的方法是async void。这具有即发即弃的语义。

从概念上讲,您的方法使用 async-await 的用法如下所示:

[Test]
public void GetSomethingTest()
{
    var service = SimpleIoc.Default.GetInstance<IService>();
    service.TryGetSomethingAsync(20).ContinueWith(t =>
    {
        var result = t.Result;
        Assert.IsTrue(result.IsSuccess);
        Assert.IsNotNull(result.ReturnValue);
    });
}

现在应该清楚问题所在了。只要TryGetSomethingAsync 返回其Task,您的测试方法就会立即返回。所以测试立即结束。既然没有抛出异常,那就是成功了。

如果您的测试框架支持 Task-returning 测试,您可以通过将其返回类型更改为 Task 而不是 void 来修复您的测试以执行您想要的操作。 p>

[Test]
public async Task GetSomethingTest()
{
    var service = SimpleIoc.Default.GetInstance<IService>();
    var result = await service.TryGetSomethingAsync(20);
    Assert.IsTrue(result.IsSuccess);
    Assert.IsNotNull(result.ReturnValue);
}

这将在概念上转化为以下内容。

[Test]
public Task GetSomethingTest()
{
    var service = SimpleIoc.Default.GetInstance<IService>();
    return service.TryGetSomethingAsync(20).ContinueWith(t =>
    {
        var result = t.Result;
        Assert.IsTrue(result.IsSuccess);
        Assert.IsNotNull(result.ReturnValue);
    });
}

注意Task continuation 是如何返回的,以便测试框架现在可以等待它,确保在认为测试完成之前所有测试代码都有时间运行。

(从技术上讲,一个框架也可以在async void 的情况下工作,但我不知道为什么这是一个很好的功能,所以我希望大多数人不会处理它。)

如果您的测试框架不支持返回任务的测试,您可以使用.Result 而不是await 来修复您的测试。

[Test]
public void GetSomethingTest()
{
    var service = SimpleIoc.Default.GetInstance<IService>();
    var result = service.TryGetSomethingAsync(20).Result;
    Assert.IsTrue(result.IsSuccess);
    Assert.IsNotNull(result.ReturnValue);
}

这只会阻塞当前线程,直到 TryGetSomethingAsync 返回的 Task 完成。

【讨论】:

  • 切换到 MSTest 并返回 Task 解决了我的问题,但感谢详细的回答,我相信它会帮助其他人!
猜你喜欢
  • 2019-11-13
  • 2016-03-20
  • 1970-01-01
  • 2014-11-24
  • 1970-01-01
  • 2018-05-06
  • 1970-01-01
  • 2018-03-01
  • 1970-01-01
相关资源
最近更新 更多