2

我一直在阅读:Testing Rx Queries using Virtual Time Scheduling

我到了“使用单元测试项目”部分(大约在页面的中间)并自己尝试了(使用 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));
}

我必须做出的一项改变是:

scheduler.Schedule(TimeSpan.FromTicks(190),
                   () => xs.Subscribe(observer1));

变成:

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

老实说,我没有掌握这种变化的影响(我没有用 C# 编码那么久!)。

结果如下:

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

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

该文档基于 V2 的 pre-RTM,所以我不确定 TestScheduler 的行为是否在 RTM 中发生了变化,或者我是否在某个地方犯了错误。如果有人能解释发生了什么,我将不胜感激。

4

1 回答 1

9

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

using System.Reactive.Concurrency;

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

public IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)

因此,当调度程序在时间 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));

确保导入 System.Reactive.Concurrency 命名空间以查找这些重载。您也可以在这里使用 ScheduleRelative,因为调度程序尚未启动,到期时间将是当前调度程序的时钟值 (= 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));

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

于 2012-10-05T10:10:34.070 回答