c# - 等到单元测试中的所有任务完成

标签 c# unit-testing asynchronous synchronization task

我有这个类我想进行单元测试:

public class SomeClass
{
    public void Foo()
    {
        Bar();
    }

    private void Bar()
    {
        Task.Factory.StartNew(() =>
        {
            // Do something that takes some time (e.g. an HTTP request)
        });
    }
}

这就是我的单元测试的样子:

[TestMethod]
public void TestFoo()
{
    // Arrange
    var obj = new SomeClass();

    // Act
    obj.Foo();
    obj.Foo();
    obj.Foo();

    // Assert
    /* I need something to wait on all tasks to finish */
    Assert.IsTrue(...);
}

因此,我需要让单元测试线程等到 Bar 方法中启动的所有任务都完成它们的工作,然后再开始我的断言。

重要:我无法更改 SomeClass

我该怎么做?

最佳答案

解决此问题的一种方法是定义您自己的任务调度程序,以便您可以跟踪嵌套任务的完成情况。例如,您可以定义一个同步执行任务的调度程序,如下所示:

class SynchronousTaskScheduler : TaskScheduler
{
    protected override void QueueTask(Task task)
    {
        this.TryExecuteTask(task);
    }

    protected override bool TryExecuteTaskInline(Task task, bool wasPreviouslyQueued)
    {
        return this.TryExecuteTask(task);
    }

    protected override IEnumerable<Task> GetScheduledTasks()
    {
        yield break;
    }
}

随后,创建这个同步任务调度程序的一个实例,并使用它来执行一个根任务,该任务反过来会产生所有“隐藏”任务。由于嵌套任务从其父级继承当前任务调度程序,所有内部任务也将在我们的同步调度程序上运行,这意味着我们最外层的 StartNew 调用只会在所有任务完成时返回。

TaskScheduler scheduler = new SynchronousTaskScheduler();

Task.Factory.StartNew(() =>
{
    // Arrange
    var obj = new SomeClass();

    // Act
    obj.Foo();
    obj.Foo();
    obj.Foo();
}, 
    CancellationToken.None,
    TaskCreationOptions.None,
    scheduler);

// Assert
/* I need something to wait on all tasks to finish */
Assert.IsTrue(...);

这种方法的缺点是您将失去任务的所有并发性;但是,您可以通过将自定义调度程序增强为并发但仍允许您跟踪执行任务的调度程序来解决此问题。

关于c# - 等到单元测试中的所有任务完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17844182/

相关文章:

c# - WCF Discovery 返回硬编码的 URL

javascript - Angularjs 服务单元测试

node.js - 将 async.js 与 Node.js 结合使用

javascript - 如何让函数等到数据库连接建立后再继续?

javascript - 将 URL 中的数据添加到传单 map

c# - Lazy<T> 如何解决需要 new() 约束的问题?

c# - Decorate-Sort-Undecorate,如何按降序对字母字段进行排序

c# - Accordion 中的自动高度 True 不起作用

javascript - mocha 如何知道事件何时在 $promise 内使用 $broadcast 在 Controller $scope 上触发?

ruby-on-rails - Controller 测试错误消息 : "ActionView::Template::Error: The asset "MyString"is not present in the asset pipeline"