我有这个类我想进行单元测试:
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/