如果任务后跟 task.start(),如何编写单元测试?

How to compose a unit test if a task is followed by task.start()?

在程序中,我们有:

var task1 = some task;
task1.start()

如果在单元测试中模拟任务结果,模拟机制会在调用 start() 之前立即返回结果,并引发“可能无法在已完成的任务上调用启动”异常。

如何解决该问题并编写有效的单元测试?

为清楚起见,在此处粘贴一个简化的示例代码,它会产生上述异常:

namespace TestTaskStart
{
    public class TestMethods : ITestMethods
    {
        public async Task<int> AlwaysReturnOne(int number)
        {
            return await Task.FromResult(1);
        }
    }
}

namespace TestTaskStart {
    public class TestInvoker
    {
        private ITestMethods testMethods;

        public TestInvoker(ITestMethods testMethods)
        {
            this.testMethods = testMethods;
        }

        public async Task<int> GetANumberWrapperTask(int number)
        {
            // just an exmple of one tasks to be called
            var task = this.testMethods.AlwaysReturnOne(number);
            task.Start();
            Task.WaitAll(task);

            return task.Result;
        }
    }
}

namespace TestTaskStart {
    [TestClass]
    public class UnitTests
    {
        ITestMethods numberGetter;
        TestInvoker testInvoker;

        [TestInitialize]
        public void Setup()
        {
            this.numberGetter = Substitute.For<ITestMethods>();
            this.testInvoker = new TestInvoker(this.numberGetter);
        }

        [TestMethod]
        public void TestGetANumberWrapper()
        {
            this.MockAlwaysReturnOneResult();
            var result = testInvoker.GetANumberWrapperTask(5).Result;
        }

        private void MockAlwaysReturnOneResult()
        {
            this.numberGetter.AlwaysReturnOne(Arg.Any<int>()).Returns(1);
        }
    }
}

Task.Start 方法只能在“冷”任务上调用,换句话说,在尚未启动的任务上。此类任务只能使用 Task 构造函数创建。通过调用使用 async 关键字实现的异步方法创建的任务是“热的”,换句话说,它们在创建时就已经开始了。来自文档:

Exceptions
InvalidOperationException
The Task is not in a valid state to be started. It may have already been started, executed, or canceled, or it may have been created in a manner that doesn't support direct scheduling.

这也是一本好书:A Tour of Task, Part 10: Promise Tasks