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

No Comments