如何通过 `Sample` 方法测试将值推送到使用 Reactive Extensions 的对象

How to test object that pushes values to using Reactive Extensions via `Sample` method

我有一个名为 ValuePusher 的 class 和一个名为 Value 的 属性 并接收类型为 ValueReceiver 的依赖项,也有一个 [=34] =] 命名为 Value。前者 class 通过 System.Reactive.Subjects.Subject<int> 对象将 'push' 值安排到后者 class 的实例。最初它一对一地推送值,但稍后它将限制使用 Sample 方法推送的值的数量 - 请注意以下代码中对此方法的注释调用:

public sealed class ValuePusher : IDisposable
{
    private readonly ValueReceiver _receiver;
    private readonly IScheduler _scheduler;
    private readonly Subject<int> _subject;

    private int _value;

    public ValuePusher(ValueReceiver receiver, IScheduler scheduler)
    {
        _receiver = receiver;
        _scheduler = scheduler;

        // Arrange to push values to `receiver` dependency
        _subject = new Subject<int>();
        _subject.ObserveOn(_scheduler)
                //.Sample(TimeSpan.FromMilliseconds(50), _scheduler)
                .SubscribeOn(_scheduler)
                .Subscribe(i => PushCurrentValueToReceiver());
    }

    public int Value
    {
        get => _value;
        set
        {
            _value = value;
            _subject.OnNext(0);
        }
    }

    private void PushCurrentValueToReceiver()
    {
        _receiver.Value = Value;
    }

    public void Dispose()
    {
        _subject?.OnCompleted();
        _subject?.Dispose();
    }
}

public class ValueReceiver
{
    public int Value { get; set; }
}

我为上面的代码写了一个单元测试,涉及一个Microsoft.Reactive.Testing.TestScheduler,通过了:

[TestMethod]
[Timeout(1000)]
public void ReceiverReceivesValueFromPusherViaScheduler()
{
    var scheduler = new TestScheduler();
    var receiver = new ValueReceiver();

    using (var pusher = new ValuePusher(receiver, scheduler))
    {
        scheduler.Start();
        pusher.Value = 1;
        scheduler.AdvanceBy(1);
        Assert.AreEqual(1, receiver.Value);
    }
}

但是,如果取消注释对 Sample 方法的调用,测试将无法完成并超时。如何更改测试代码或生产代码以验证在使用 Sample 时是否将值推送到接收对象?

源代码:https://github.com/DanStevens/Whosebug71409012

超时的原因,好像是.Sample(...)scheduler.Start()的组合。

scheduler.Start() 尝试执行已安排的所有内容,但我认为 Sample() 一直在安排样本,因此 scheduler.Start() 永远不会完成。

因此,如果您删除 scheduler.Start(),然后改为这样做:

...
// Following line instead of scheduler.Start(), needed because of the .SubscribeOn(...) call
scheduler.AdvanceBy(1);

pusher.Value = 1;
scheduler.AdvanceBy(TimeSpan.FromMilliseconds(50).Ticks);
Assert.AreEqual(1, receiver.Value);
...

无论是否调用 .Sample(...),它都应该工作。

[编辑] 根据 Dan Stevens 的评论。