Как стать автором
Обновить

Комментарии 2

Хорошая тема затронута в статье, важная.

Как решили проблему с асинхронным кодом из-за Combine

Актуальный кейс с интересным решением. Только код асинхронный не из-за combine, а из-за реализации. Код мог бы быть синхронным и с combine.

Как мы решили проблему с асинхронным кодом из-за замыканий

Тоже самое. Так же бросаются в глаза фразы "задачи на background-потоке", при том что работаете вы с очередями.

Он заблокирует вызываемый поток до тех пор, пока все задачи на background queue не завершатся.

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

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

Но вообще, по хорошему в тестах нужно стремится свести к нулю любую асинхронность. Для этого нужно концентрировать силы не на combine или queues, а на месте где она возникает. Как правило, это те самые зависимости которые вы заменяете заглушками.

Как с комбайном, так и с замыканиями тестовая реализация может оставаться синхронной.
На мой взгляд это самый важный момент в поднятом вопросе, но вы об этом ничего не сказали.

Хорошие замечания, спасибо.

Только код асинхронный не из-за combine, а из-за реализации. Код мог бы быть синхронным и с combine.

В случае с combine код будет синхронный только в двух случаях:

  1. если не указать receive(on:)/subscribe(on:)

  2. передать ImmediatedScheduler.shared в качестве scheduler'а в функции receive(on:)/subscribe(on:)

В остальных случаях так или иначе код будет асинхронный. Эта асинхронность может быть вызвана использованием операторов debounce/throttle либо из-за использования в качестве scheduler какой-то приватной очереди. Да даже использование DispatchQueue.main либо RunLoop.main в качестве scheduler заставит код выполняться асинхронно. Соответсвенно и в тесте эту асинхронность придётся бы обрабатывать.

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

Не совсем так. Если код вызывается на очереди q1 и на этой очереди мы вызываем q2.sync {}, то q1 будет ждать пока все задачи на q2 завершатся. Другими словами это верно для того потока с которого произошел вызов q.sync {}.

Но вообще, по хорошему в тестах нужно стремится свести к нулю любую асинхронность. Для этого нужно концентрировать силы не на combine или queues, а на месте где она возникает. Как правило, это те самые зависимости которые вы заменяете заглушками.

Согласен, но это не всегда возможно. Бывают случаи, когда, чтобы полностью избавиться от асинхронности нужно переписать не мало кода. А бывает, что избавиться вовсе невозможно, как в примере с debounce. Ну и не нужно забывать, что иногда нужно тестировать непосредственно асинхронное поведение, например, если используется параллельная очередь.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий