Модульное тестирование поведения Kotlin ConflatedBroadcastChannel

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

На этом этапе я наткнулся на требование иметь BehaviorSubject -подобное поведение , где можно подписаться на поток данных и получать самое последнее значение при подписке. Как я узнал, Channel обеспечивают очень похожее поведение в Котлине, поэтому Я решил попробовать.

Из этой статьи я узнал, что _3 _ - это тип канала, который имитирует BehaviorSubject, поэтому я объявил следующее:

class ChannelSender {

    val channel = ConflatedBroadcastChannel<String>()

    fun sendToChannel(someString: String) {
         GlobalScope.launch(Dispatchers.Main) { channel.send(someString) }
    }
}

Для прослушивания канала делаю так:


    class ChannelListener(val channelSender: ChannelSender) {
        fun listenToChannel() {
            channelSender.channel.consumeEach { someString ->
                if (someString == "A") foo.perform() 
                else bar.perform()
            }
        }
    }

Это работает, как ожидалось, но на данный момент у меня возникли трудности с пониманием того, как проводить модульное тестирование ChannelListener.

Я пытался найти что-то связанное с здесь, но ни один из example-channel-**.kt классов не помог.

Любая помощь, предложение или исправление, связанные с моими неверными предположениями, приветствуются. Спасибо.


person azizbekian    schedule 02.07.2019    source источник
comment
А как насчет github.com/Kotlin/ kotlinx.coroutines / tree / master / (в частности, github.com/Kotlin/kotlinx.coroutines/blob/master/)?   -  person Alexey Romanov    schedule 02.07.2019
comment
@AlexeyRomanov, там много кода, позвольте мне проанализировать. Спасибо за совет!   -  person azizbekian    schedule 02.07.2019
comment
@AlexeyRomanov, спасибо за помощь, это действительно привело меня в правильное направление.   -  person azizbekian    schedule 02.07.2019


Ответы (1)


С помощью Алексея мне удалось получить следующий код , что отвечает на вопрос:

class ChannelListenerTest {

  private val val channelSender: ChannelSender = mock()

  private val sut = ChannelListener(channelSender)
  private val broadcastChannel = ConflatedBroadcastChannel<String>()

  private val timeLimit = 1_000L
  private val endMarker = "end"

  @Test
  fun `some description here`() = runBlocking {
    whenever(channelSender.channel).thenReturn(broadcastChannel)

    val sender = launch(Dispatchers.Default) {
      broadcastChannel.offer("A")
      yield()
    }

    val receiver = launch(Dispatchers.Default) {
      while (isActive) {
        val i = waitForEvent()
        if (i == endMarker) break
        yield()
      }
    }

    try {
      withTimeout(timeLimit) {
        sut.listenToChannel()
        sender.join()
        broadcastChannel.offer(endMarker) // last event to signal receivers termination
        receiver.join()
      }
      verify(foo).perform()
    } catch (e: CancellationException) {
      println("Test timed out $e")
    }
  }

  private suspend fun waitForEvent(): String =
      with(broadcastChannel.openSubscription()) {
        val value = receive()
        cancel()
        value
      }

}
person azizbekian    schedule 02.07.2019