Bending Time with the Reactive Extensions
The latest releases of the Reactive Extensions for .Net include an abstract VirtualScheduler and a concrete implementation called TestScheduler.
So now it’s possible test time dependent code without relying on the passage of time (or tide).
Here’s a sample of code that would take 3 days to complete in the real
[Fact(Timeout = 1000)]
public void TestScheduler()
{
List<long> actual = new List<long>();
Observable.Interval(TimeSpan.FromDays(1), _testSched)
.Take(3)
.Subscribe(actual.Add);
_testSched.Run();
Assert.Equal(new[] { 0L, 1, 2 }, actual.ToArray());
}
Notice that I didn’t use a blocking call, such as
.Take(3).ToEnumerable().ToArray()
to obtain a the values from the interval. The TestScheduler runs on the current thread, and as a result blocking calls never complete.
Here’s another example where we run for a specific duration. Usefull when testing Observables that never end
[Fact]
public void TestOneElementSlidingWindow()
{
List<SlidingWindow<Timestamped<int>>> actual = new List<SlidingWindow<Timestamped<int>>>();
var oneBeat = Observable.Return<int>(1, _testSched).Timestamp(_testSched);
var sWindow = oneBeat.ToSlidingWindow(_oneSecond, _oneSecond, _testSched);
sWindow.Subscribe(slw => actual.Add(slw));
_testSched.RunTo(_testSched.FromTimeSpan(TimeSpan.FromSeconds(3)));
Assert.Equal(2, actual.Count);
Assert.Equal(1, actual[0].Added.Count());
Assert.Equal(1, actual[0].Current.Count());
Assert.Equal(0, actual[0].Removed.Count());
Assert.Equal(0, actual[1].Added.Count());
Assert.Equal(0, actual[1].Current.Count());
Assert.Equal(1, actual[1].Removed.Count());
}
Code samples updated at http://code.msdn.microsoft.com/RxDemos
Also - Jeffrey van Gogh promises more to come on #c9