如何对使用 Task.WhenAll 方法的方法进行单元测试

3

假设我们有以下类:

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执行完毕,因此输出会有所不同。在不更改方法签名(从void到Task)的情况下,有没有办法使用NUnit测试该方法的完整运行?


2
Task.WhenAll 返回一个任务对象,你需要使用 await 来等待它的完成。目前的写法并没有实际执行任何操作。 - Yacoub Massad
@YacoubMassad:如果你在一个简单的控制台应用程序中运行MethodToBeTested方法,它会显示10条消息。但是如果你从单元测试中运行相同的方法,结果会有所不同:它可能显示三条、四条或者一条消息,这取决于单元测试完成的速度。 - kord
@kord,我认为在你的控制台应用程序中,你可以通过使用Console.ReadLine()或类似的方法来暂停执行。通过这样做,你可以让MethodToBeTested运行的任务完成。 - Yacoub Massad
@GrantWinney:没错,在这个例子中,它没有抛出异常的事实。 - kord
@YacoubMassad:对的,它可以是一个在结尾使用Console.ReadLine()的控制台应用程序,也可以是一个持续运行的Windows服务。 - kord
2个回答

1

使用 GetAwaiter().GetResult() 可以确保异步调用运行完成。在这里阅读更多 关于此方法和 await 的区别

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

0

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接