Unit-тесты и оператор of() библиотеки RxJs

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

Вдогонку к недавнему выпуску про тестирование асинхронного кода, хочется добавить, что нужно быть очень внимательным разработчиком, когда какая-либо из ваших функций возвращает Observable<void>.

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

Тут и кроется одна неприятная особенность.

Неважно в рабочем ли коде или в тестах, когда мы возвращаем результат of(), то внезапно получаем зависший намертво тест. Несмотря на то что коллбэк done() вызывается в правильном месте.

Например, вот такой фрагмент из юнит-теста:

fakeDependency.registerShipment.and.returnValue(of());

service.registerShipment().subscribe(() => {
   expect(clearSpy).toHaveBeenCalled();
   done();
});

Здесь метод registerShipment, изнутри возвращает метод зависимости fakeDependency.registerShipment с возвращаемым типом Observable<void>.

И этот тест повиснет на выполнении, а в конечном итоге отвалится с ошибкой таймаута. Потому что observable ничего не пришлет и соответственно не завершится.

А все потому, что оператор of() делает следующее:

Emit variable amount of values in a sequence and then emits a complete notification.

документация RxJS

То есть, оператор отправляет переменное количество значений, а затем завершается.

Но мы не передаем ничего внутри of(), соответственно, никаких значений не отправляется, Observable не завершается, и подписка на него в тесте зависает.

Поправить все это очень легко, достаточно указать undefined в скобках of() и проблема решена:

fakeDependency.registerShipment.and.returnValue(of(undefined));

service.registerShipment().subscribe(() => {
    expect(clearSpy).toHaveBeenCalled();
    done();
});

Будте аккуратны с возвращаемыми вручную значениями Observable и обязательно пишите юнит-тесты на этот код.

На этом все. А теперь пойдемте переписывать все пустые операторы of() там, где должен был быть Observable<void>.


Posted

in

, ,

by

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *