【发布时间】:2020-03-24 02:24:26
【问题描述】:
我想测试一个应该连续运行直到被杀死的任务。假设正在测试以下方法:
public class Worker
{
public async Task Run(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
// do something like claim a resource
}
catch (Exception e)
{
// catch exceptions and print to the log
}
finally
{
// release the resource
}
}
}
}
还有一个测试用例
[TestCase]
public async System.Threading.Tasks.Task Run_ShallAlwaysReleaseResources()
{
// Act
await domainStateSerializationWorker.Run(new CancellationToken());
// Assert
// assert that resource release has been called
}
问题是任务永远不会终止,因为从未请求取消。最终我想创建一个像MockRepository.GenerateStub<CancellationToken>() 这样的CancellationToken 存根,并告诉它对IsCancellationRequested 的哪个调用返回true,但CancellationToken 不是引用类型,所以这是不可能的。
所以问题是如何在 Run 执行 n 迭代然后终止的地方进行测试?是否可以不重构Run?
【问题讨论】:
-
var tokenSource = new CancellationTokenSource(); Task.Run(async () => await Task.Delay(1000); tokenSource.Cancel()); await domainStateSerializationWorker.Run(tokenSource.Token);之类的东西会在 1 秒后取消 -
所以在 n 次迭代后终止是不可能的,但在某个定义的时间后它是
-
@Selvin 使用这种方法,测试结果将是不确定的。我希望
Run运行xiterations,而不是x秒 -
您可以模拟一些存储工作结果的对象并从中取消(如果在
do something like claim a resource中您有类似observer.SendResult(...);的内容,那么您可以尝试模拟observer.SendResult并取消令牌在 n 次调用后)....没有更多代码/上下文问题是无法回答的 -
你也许可以用一些奇怪的反射代码到达那里,但重构
Run——即使你最初不想这样做——可能是最(成本)有效的方式你想要什么。
标签: c# unit-testing asynchronous rhino-mocks