Reactive Extensions v2中的TestScheduler如何工作

Ger*_*els 2 unit-testing system.reactive

我一直在读这个:使用虚拟时间调度测试Rx查询

我到了"使用单元测试项目"部分(大约在页面的一半)并自己尝试(使用VS2012和MSTest),但我的结果与文档中的结果不同.具体来说,我的断言失败了.

这是我的测试代码:

[TestMethod]
public void TestMethod1()
{
    var scheduler = new TestScheduler();

    var xs = scheduler.CreateColdObservable(
        OnNext(10, 42),
        OnCompleted<int>(20));

    var observer1 = scheduler.CreateObserver<int>();
    scheduler.Schedule(TimeSpan.FromTicks(190), 
                       (s, t) => xs.Subscribe(observer1));

    var observer2 = scheduler.CreateObserver<int>();
    scheduler.Schedule(TimeSpan.FromTicks(220), 
                       (s, t) => xs.Subscribe(observer2));

    scheduler.Start();

    observer1.Messages.AssertEqual(
        OnNext(200, 42),
        OnCompleted<int>(210));

    observer2.Messages.AssertEqual(
        OnNext(230, 42),
        OnCompleted<int>(240));
}
Run Code Online (Sandbox Code Playgroud)

我必须做的一个改变是:

scheduler.Schedule(TimeSpan.FromTicks(190),
                   () => xs.Subscribe(observer1));
Run Code Online (Sandbox Code Playgroud)

成为:

scheduler.Schedule(TimeSpan.FromTicks(190), 
                   (s, t) => xs.Subscribe(observer1));
Run Code Online (Sandbox Code Playgroud)

说实话,我没有意识到这种变化的影响(我没有在C#中编写那么久!).

以下是结果:

Assert.Fail failed. 
Expected: [OnNext(42)@200, OnCompleted()@210]
Actual..: [OnNext(42)@11, OnCompleted()@21]
Run Code Online (Sandbox Code Playgroud)

我理解它的方式是我创建一个冷可观察量,它将在第10个刻度上返回值42,并且序列在第20个刻度处完成.然后,我创建和观察者订阅这个观察者,表示我希望计划从标记190开始.因此,在标记200(190 + 10)处测试值42,在标记210处测试完成时间.然而,我得到标记11和分别为21.

该文档基于V2的RTM之前,因此我不确定TestMcheduler的行为是否已在RTM中更改,或者我是否在某处犯了错误.如果有人能解释发生了什么,我会很感激.

小智 8

您似乎忘记了导入System.Reactive.Concurrency命名空间,其中定义了您要使用的计划重载.这解释了为什么你必须改变代码 - 便利扩展方法可能没有出现:

using System.Reactive.Concurrency;
Run Code Online (Sandbox Code Playgroud)

您正在使用的Schedule的重载是用于立即调度的重载,将TimeSpan值作为TState参数传递:

public IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
Run Code Online (Sandbox Code Playgroud)

因此,当调度程序在时间0开始时,将立即执行对xs的预订.每个工作项增加时钟(在测试调度程序上不会同时发生任何事件,模拟单个执行线程),因此您将看到在时间1的一个序列订阅和在时间2的另一个序列订阅

一种可能的解决方法是使用以下内容:

var observer1 = scheduler.CreateObserver<int>();
scheduler.ScheduleAbsolute(190, () => xs.Subscribe(observer1));

var observer2 = scheduler.CreateObserver<int>();
scheduler.ScheduleAbsolute(220, () => xs.Subscribe(observer2));
Run Code Online (Sandbox Code Playgroud)

确保导入System.Reactive.Concurrency命名空间以查找这些重载.您也可以使用ScheduleRelative,因为调度程序尚未启动,到期时间将是当前调度程序的Clock值(= 0)加上指定的相对持续时间.

或者,您也可以使用DateTimeOffset或TimeSpan重载来浏览IScheduler API表面.小心选择正确的过载(使用F12 - 转到定义 - 查看您选择的过载).

var observer1 = scheduler.CreateObserver<int>();
scheduler.Schedule(TimeSpan.FromTicks(190), () => xs.Subscribe(observer1));

var observer2 = scheduler.CreateObserver<int>();
scheduler.Schedule(TimeSpan.FromTicks(220), () => xs.Subscribe(observer2));
Run Code Online (Sandbox Code Playgroud)

同样,请确保使用using指令导入System.Reactive.Concurrency命名空间以查看此重载:-).