反应式扩展测试调度程序模拟时间流逝

本文关键字:时间 流逝 模拟 调度程序 扩展 测试 反应式 | 更新日期: 2023-09-27 18:35:11

>我正在使用 RX 调度程序类。Schedule(DateTimeOffset, Action>) stuff.基本上,我有一个可以再次计划自己的计划操作。

法典:

public SomeObject(IScheduler sch, Action variableAmountofTime)
{
    this.sch = sch;
    sch.Schedule(GetNextTime(), (Action<DateTimeOffset> runAgain =>
    {
        //Something that takes an unknown variable amount of time.
        variableAmountofTime();
        runAgain(GetNextTime());
    });
}
public DateTimeOffset GetNextTime()
{
    //Return some time offset based on scheduler's 
    //current time which is irregular based on other inputs that i have left out.
    return this.sch.now.AddMinutes(1);
}
我的

问题是关于模拟时间变量的时间量可能需要的时间量,并测试我的代码是否按预期运行,并且仅触发按预期调用它。

我尝试在委托中提前测试调度程序的时间,但这不起作用。我编写的代码示例不起作用。假设 GetNextTime() 只安排一分钟。

[Test]
public void TestCallsAppropriateNumberOfTimes()
{
    var sch = new TestScheduler();
    var timesCalled = 0;
    var variableAmountOfTime = () => 
        { 
            sch.AdvanceBy(TimeSpan.FromMinutes(3).Ticks); 
            timescalled++; 
        };
    var someObject = new SomeObject(sch, variableAmountOfTime);
    sch.AdvanceTo(TimeSpan.FromMinutes(3).Ticks);
    Assert.That(timescalled, Is.EqualTo(1));
}

由于我想进入未来 3 分钟,但执行需要 3 分钟,因此我想看到这只触发 1 次。.相反,它会触发 3 次。

如何使用测试调度程序模拟在执行过程中花费时间的内容。

反应式扩展测试调度程序模拟时间流逝

好问题。不幸的是,Rx v1.x 和 Rx v2.0 Beta 目前不支持此功能(但请继续阅读)。让我向您解释嵌套 Advance* 调用的复杂性。

基本上,Advance* 意味着启动调度程序以运行工作,直到指定的点。这涉及在表示虚拟调度程序中的时间流的单个逻辑线程上按顺序运行工作。允许嵌套高级*呼叫会引发一些问题。

首先,嵌套的 Advance* 调用是否应该导致嵌套的工作线程循环运行?如果是这种情况,我们不再模仿单个逻辑执行线程,因为当前工作项将被中断以支持运行内部循环。事实上,Advance* 会导致隐式收益,在处理完所有嵌套工作之前,不允许在 Advance* 调用后的其余工作(现在到期)运行。这导致了未来工作不能依赖(或等待)过去的工作来完成其执行的情况。一种出路是引入真正的物理并发,这首先击败了虚拟时间和历史调度程序的各种设计点。

或者,如果嵌套的 Advance* 调用以某种方式与最顶层的工作线程循环调度调用(Advance* 或 Start)通信,则可能需要延长其到期时间,因为嵌套调用已请求前进到超出原始到期时间的点。现在各种各样的事情都变得奇怪了。时钟不会反映从 Advance* 返回后的变化,并且最顶层的呼叫不再在可预测的时间结束。

对于 Rx v2.0 RC(下个月推出),我们查看了此场景,并认为 Advance* 不是模拟"时间滑移"的正确选择,因为它需要重载含义,具体取决于调用它的上下文。相反,我们引入了一种 Sleep 方法,该方法可用于将时间从任何上下文向前滑移,而不会产生运行工作的副作用。将其视为设置 Clock 属性的一种方式,但具有防止时光倒流的方法。这个名字也清楚地反映了意图。

除上述内容外,为了减少嵌套 Advance* 调用无效的意外因素,我们让它检测到这种情况并在嵌套上下文中抛出 InvalidOperationException。另一方面,睡眠可以从任何地方调用。

最后一点。事实证明,在处理时间方面,我们需要完全相同的功能来完成我们在 Rx v2.0 RC 中所做的工作。一些测试需要一种确定性的方式来模拟由于执行用户代码而造成的时间延迟,这些代码可能需要任意长的时间(想想OnNext处理程序,例如Observable.Interval)。

希望这有帮助...请继续关注我们未来几周的Rx v2.0 RC版本!

-巴特(Rx团队)