【问题标题】:How to unit test a method that uses Task.WhenAll如何对使用 Task.WhenAll 的方法进行单元测试
【发布时间】:2022-03-14 14:42:45
【问题描述】:

假设我们有以下类:

class SampleClass
{
    private readonly IList<int> _numberList = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    public void MethodToBeTested()
    {
        Task.WhenAll(_numberList.Select(async number => { await Task.Run(() => { ProcessNumber(number); }); }));
    }

    private static void ProcessNumber(int number)
    {
        Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId} Number:{number}");
        Thread.Sleep(1000);
    }
}

我们添加以下单元测试:

[Test]
public void TestMethodToBeTested()
{
    var sampleClass = new SampleClass();
    _sampleClass.MethodToBeTested();
}

问题在于,当测试运行时,它不会等待 MethodToBeTested 完成执行,因此输出会有所不同。有没有办法使用 NUnit 测试这个方法的完整运行,而不改变方法签名(从 void 到 Task)?

【问题讨论】:

  • Task.WhenAll 返回一个任务对象,您必须将它发送给await。现在的样子,它什么也没做。
  • @YacoubMassad:如果您运行 MethodToBeTested 方法,在一个简单的控制台应用程序中,它将显示 10 条消息。如果您从单元测试中运行相同的方法,它会有所不同:它显示三、四、一,取决于单元测试完成的速度。
  • @kord,我认为在您的控制台应用程序中,您可以使用 Console.ReadLine() 或类似的东西来暂停执行。通过这样做,您允许MethodToBeTested 运行的任务完成。
  • @GrantWinney:对:在这个例子中,它不会抛出异常。
  • @YacoubMassad:对:它可以是一个控制台应用程序,末尾带有 Console.ReadLine(),也可以是一个持续运行的 Windows 服务。

标签: c# unit-testing nunit task


【解决方案1】:

使用GetAwaiter().GetResult() 将确保异步调用运行完成。阅读更多关于approach vs await here

public void MethodToBeTested()
{
    Task.WhenAll(_numberList.Select(async number => { await Task.Run(() => { ProcessNumber(number); }); })).GetAwaiter().GetResult();
}

【讨论】:

    【解决方案2】:

    以防万一有人有使用网络的任务:

    理论上,单元测试不应该有网络调用,因此您不需要运行任务。您可以伪造调用 (Task.FromResult(true)),但如果您真的想进行网络调用,请考虑集成测试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-29
      • 1970-01-01
      • 2012-06-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多