我有以下要测试的功能
/// Items are processed asynchronously via fn as they arrive. However
/// if an item arrives before the last asynchronous operation has
/// completed then the cancellation token passed to fn will be
/// triggered enabling the task to be canceled in a best effort
/// way.
public static IObservable<U> SelectWithCancellation<T, U>
( this IObservable<T> This
, Func<CancellationToken, T, Task<U>> fn
)
{
return This
.Select(v=>Observable.FromAsync(token=>fn(token, v)))
.Switch();
}
我希望对其进行测试,我能想到的最好的作品如下。首先我创建一个可以取消的长时间运行的任务
public Task<string> JobTask
( CancellationToken token
, string input
)
{
return Task.Factory.StartNew(() =>
{
if ( input == "C" || input == "E" )
{
while ( !token.IsCancellationRequested ) ;
}
return input;
}
);
}
然后我测试它是否真的可以工作
public class SelectWithCancelationSpec : ReactiveTest
{
TestScheduler _Scheduler = new TestScheduler();
[Fact]
public void ShouldWork()
{
var o = _Scheduler.CreateHotObservable
( OnNext(100, "A")
, OnNext(200, "B")
, OnNext(300, "C")
, OnNext(400, "D")
, OnNext(500, "E")
, OnNext(500, "F")
);
List<string> actual = new List<string>();
o
.SelectWithCancellation(JobTask)
.Subscribe(v => actual.Add(v));
var delay = 100;
_Scheduler.AdvanceTo(150);
Thread.Sleep(delay);
_Scheduler.AdvanceTo(250);
Thread.Sleep(delay);
_Scheduler.AdvanceTo(350);
Thread.Sleep(delay);
_Scheduler.AdvanceTo(450);
Thread.Sleep(delay);
_Scheduler.AdvanceTo(550);
Thread.Sleep(delay);
_Scheduler.AdvanceTo(650);
var expected = new[] { "A", "B", "D", "F" };
actual
.ShouldBeEquivalentTo(expected);
}
}
问题是我不得不引入real time
测试。这是因为我模拟的 JobTask 运行在线程池之外的真实线程上,并且不尊重测试调度程序的虚拟时间。发生的情况是,如果我不在AdvanceTo
两次调用之间设置延迟,我在测试中丢弃的消息比我预期的要多,因为 JobTask 处理时间太长。
问题是。如何创建一个尊重虚拟时间并允许我测试是否可以成功删除预期消息的 JobTask。