如何在ReplaySubject时间窗口中使用TestScheduler

时间:2014-08-03 06:30:24

标签: c# system.reactive reactive-programming

我有一个测试代码示例:

    [Fact]
    public void Should_only_contain_most_recent() {
        var window = TimeSpan.FromMilliseconds(200);
        var results = new ReplaySubject<long>(window);
        results.OnNext(1);
        results.OnNext(2);
        System.Threading.Thread.Sleep(50);
        results.OnNext(3);
        System.Threading.Thread.Sleep(50);
        results.OnNext(4);
        System.Threading.Thread.Sleep(200);
        results.OnNext(5);
        results.OnCompleted();
        var items = results.ToEnumerable();
        Assert.True(items.SequenceEqual(new long [] { 5 }));
    }

我想使用Microsoft.Reactive.Testing包中的TestScheduler,因为我想摆脱这里的睡眠。

我已经尝试过这样的事情。

    [Fact]
    public void Should_only_contain_most_recent() {
        var scheduler = new TestScheduler();
        var window = TimeSpan.FromMilliseconds(200);
        var results = new ReplaySubject<long>(window /* Never finishes when add the scheduler here.*/);
        results.OnNext(1);
        results.OnNext(2);
        scheduler.Schedule(TimeSpan.FromMilliseconds(50), () => results.OnNext(3));
        scheduler.Schedule(TimeSpan.FromMilliseconds(50), () => results.OnNext(4));
        scheduler.Schedule(TimeSpan.FromMilliseconds(200), () => results.OnNext(5));
        scheduler.Schedule(TimeSpan.FromMilliseconds(210), results.OnCompleted);
        scheduler.Start();

        var items = results.ToEnumerable();
        Assert.True(items.SequenceEqual(new long[] { 5 }));
    }

但我错过了一些东西。

1 个答案:

答案 0 :(得分:1)

据推测,您正在尝试测试ReplaySubject的重放行为。问题是你需要两次启动TestScheduler。它只会运行直到所有已调度的事件都被执行 - 但是我们需要在没有任何订阅者的情况下加载ReplaySubject以便它具有它将重放的事件 - 然后在订阅者附加后再次运行调度程序。

以下是编写此测试的惯用方法:

首先,我将source设置为我们需要的事件。通过从ReactiveTest派生测试类,您可以利用OnXXX辅助方法更轻松地创建源事件。

我们准备好源代码流后,我们就可以为此ReplaySubject订阅,并在Start上调用TestScheduler。这将运行虚拟时间直到最后一个预定事件(T = 300ms) - 我通过转储超时来证明这一点。

现在,我们使用TestScheduler的{​​{1}}方法为结果创建记录器并将其订阅到CreateObserver

现在我们再次启动ReplaySubject - 这将从T = 300ms开始运行时钟,直到刷新新创建的预定事件。这些是TestScheduler需要重播的事件 - 200ms窗口内的事件。请注意,这些将在T = 300ms + 1刻度,+ 2刻度和+3刻度处发出 - 这是因为ReplaySubject具有1刻度分辨率。

以下是代码:

TestScheduler