Тестирование издателя стало проще

После использования ReactiveCocoa, RxSwift в течение некоторого времени у меня появилась возможность перейти на фреймворк Apple Combine. Конечно, теперь мне нужно было провести модульное тестирование всех этих издателей.

Работа с потоками дает большие преимущества, такие как более чистый код, меньшее количество побочных эффектов, меньшие классы. Но у него есть и один недостаток, тестирование немного сложнее.

Что я сделал, так это то, что я попытался немного упростить тестирование.

Проблема

Представим, что у нас есть протокол Device, который возвращает текущее состояние устройства.

protocol IDevice {
 func deviceState() -> String
}

Кроме того, у нас есть UseCase, где мы хотим получить логическое значение, если устройство включено или выключено в соответствии с его состоянием. Без Combine наш код выглядел бы так:

В нашем модульном тесте нам понадобится IDevice-Mock, где мы имитируем deviceState(), чтобы мы могли протестировать каждый случай.

Опубликованный подход

Теперь, с помощью Combine, мы изменим функции, сделав их более «реактивными». Итак, мы заменили возвращаемые значения на Publishers.

Тестирование стало непростым делом. Нам нужно будет подписаться на isOn() и поиздеваться над deviceState(). Итак, давайте сделаем это.

Теперь мы создали массив expectedValues, в котором перечисляем значения, которые мы ожидаем от Publisher<Bool> ,, на которые мы подписались, сохранили значения, которые были отправлены в приемник, а затем отправили состояния устройства с помощью deviceStateSub.

Конечно, это не сработает, если выходные данные Издателя не равноценны.

Итак, что я сделал, я написал несколько вспомогательных функций, которые упростят мне жизнь.

Решение

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

Вспомогательная функция вернет ожидание. Затем нам нужно просто отправить завершение из макета и дождаться ожидания.

Теперь мы добавляем вспомогательную функцию expectValue к нашему расширению, которая будет проверять равные значения:

В параметре equals функции expectValue мы даем значения, которые ожидаем от .isOn() Издателя. После этого мы отправляем значения из нашей темы deviceStateSub.

Итак, мы ожидаем, что когда deviceState равно Off, isOn() вернет false, если On, он должен вернуть true.

Наконец, у нас есть аналогичная функция для обработки более сложных проверок. Представьте, что в нашем IsOnUseCase есть еще одна функция, которая возвращает не равноправный пользовательский объект с текстом.

Наша тестовая функция expectValue , также принимает список закрытий .

Теперь нам нужно будет использовать замыкания, чтобы проверить результат isOn() Publisher.

Надеюсь, вы нашли вышеуказанные функции полезными.

Удачного модульного тестирования.