等到所有任务完成unit testing

我有这门课,我想进行unit testing:

public class SomeClass { public void Foo() { Bar(); } private void Bar() { Task.Factory.StartNew(() => { // Do something that takes some time (eg an HTTP request) }); } } 

这就是我的unit testing的样子:

 [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(...); } 

所以,我需要让unit testing线程等到在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 GetScheduledTasks() { yield break; } } 

随后,创建此同步任务调度程序的实例,并使用它来执行根任务,从而生成所有“隐藏”任务。 由于嵌套任务从其父级inheritance当前任务调度程序,因此所有内部任务也将在我们的同步调度程序上运行,这意味着我们最外层的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(...); 

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

 Task.WaitAll(the, list, of, task, objects, you, need, to, wait, on); 

如果它是一个void async方法,那么你不能这样做。 设计被打破了。 他们只是为了火而忘记。

不确定您是否被允许进行此更改,但我让它工作这样做:

 namespace ParallelProgramming.Playground { public class SomeClass { public Task Foo() { return Bar(); } private static Task Bar() { return Task.Factory.StartNew(() => { Console.WriteLine("I fired off. Thread ID: {0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(5000); return true; //or whatever else you want. }); } } [TestClass] public class StackOverflow { [TestMethod] public void TestFoo() { // Arrange var obj = new SomeClass(); var results = new ConcurrentBag(); var waitForMe = Task.Factory.StartNew(() => { // Act results.Add(obj.Foo()); results.Add(obj.Foo()); results.Add(obj.Foo()); return true; }); Task.WaitAll(waitForMe); // Assert /* I need something to wait on all tasks to finish */ Assert.IsTrue(waitForMe.Result); Assert.AreEqual(3, results.Count); } } }