Тестирование IConnectableObservable с помощью TestScheduler - PullRequest
2 голосов
/ 03 мая 2020

Хорошо, уже поздно, но я не могу понять, почему происходит следующее.

Я пытаюсь проверить следующее (упрощенно) IConnectableObservable<long>:

private const int PollingIntervalMinutes = 5;

private IConnectableObservable<long> CreateObservable(IScheduler scheduler)
{
    return Observable
        .Interval(TimeSpan.FromMinutes(PollingIntervalMinutes), scheduler)
        .StartWith(0)
        .Publish();
}

Если я проверю «длинную руку» следующим образом, тест пройден:

[Test]
public void ShouldReturnExpectedNumberOfMessagesLongHand()
{
    var scheduler = new TestScheduler();
    var observed = scheduler.CreateObserver<long>();

    var observable = CreateObservable(scheduler);

    observable.Subscribe(observed);

    observable.Connect();

    Assert.That(observed.Messages.Count, Is.EqualTo(1));

    scheduler.AdvanceBy(TimeSpan.FromMinutes(PollingIntervalMinutes).Ticks);

    Assert.That(observed.Messages.Count, Is.EqualTo(2));

    scheduler.AdvanceBy(TimeSpan.FromMinutes(PollingIntervalMinutes).Ticks);

    Assert.That(observed.Messages.Count, Is.EqualTo(3));

    scheduler.AdvanceBy(TimeSpan.FromMinutes(PollingIntervalMinutes).Ticks);

    Assert.That(observed.Messages.Count, Is.EqualTo(4));
}

Однако, если я использую подход TestScheduler.Start - как показано ниже, - тест зависает и никогда не достигает значения Assert:

[Test]
public void ShouldReturnExpectedNumberOfMessages()
{
    var scheduler = new TestScheduler();

    var observable = CreateObservable(scheduler);

    var observed = scheduler.Start(() => { observable.Connect(); return observable; }, TimeSpan.FromMinutes(PollingIntervalMinutes * 3).Ticks);

    Assert.That(observed.Messages.Count, Is.EqualTo(4));
}

Поместив точку останова в наблюдаемую (то есть на дополнительную Select или Do), я могу видеть, что вызов scheduler.Start вызывает вращение базовой наблюдаемой (т.е. достигает точки останова тысячи раз) вместо соблюдения запланированного времени.

Я пробовал различные способы вызова Connect на IConnectableObservable (т. е. подключение до вызова start, планирование вызова Connect в TestScheduler и т. д. c), но безрезультатно.

Это определенно связано с тестированием IConnectableObservable, поскольку удаление Publish (т. е. превращение его в обычную наблюдаемую на холоду) делает тестовый проход успешным.

Проверка работоспособности и / о Буду очень признателен за ваши предложения.

1 Ответ

3 голосов
/ 03 мая 2020

Нераспределенный издатель снова наносит удар.

Обычные подозреваемые:

var observable = CreateObservable(scheduler);    
scheduler.Start(() => { observable.Connect(); return observable; }, ...

Чтобы фактически удалить интервальный таймер, вам нужен способ удалить подписку от observable.Connect(), а не от подписки методом Start.

После подключения ваш интервал запускает элементы (настолько быстро, насколько это возможно) с помощью планировщика тестов, и отмена подписки фактически ничего не делает, оставляя его включенным - и планировщик тестов никогда не завершится.

Одним из способов обеспечения утилизации ресурсов, в общем случае, является использование Using.

scheduler.Start(() => Observable.Using(() => observable.Connect(), _ => observable), ...

Но более простым способом обеспечения исходного соединения с publi sh является утилизируется, когда наблюдаемое ниже по течению отписывается от, использовать RefCount.

scheduler.Start(() => CreateObservable(scheduler).RefCount(), ...
...