如果任务后跟 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.
在程序中,我们有:
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
TheTask
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.