https://kotlinlang.org logo
#coroutines
Title
# coroutines
p

pdegand

05/24/2018, 10:21 AM
Hello, what is the goody way to test a function that's consuming a channel ? My function looks like this :
Copy code
suspend fun start(channel: ReceiveChannel<Event>) {
  launch(coroutineContext) {
    for (event in channel) {
      val view = // do something with each the event
      withContext(context = UI) {
        _evenementLiveData.value = view
      }
    }
  }
}
and my test looks like this :
Copy code
@Test
fun testStart() = runBlocking {
  //given
  val channel = ConflatedChannel<Event>()
  val observer = mock<Observer<EvenementDetailView>>()
  presenter.evenementLiveData.observeForever(observer)

  val evenement = // create an event

  //when
  presenter.start(channel)
  channel.send(event)


  //then
  assertThat(presenter.evenementLiveData.value).isEqualTo(expectedView)
}
However, as my method start is launching a coroutine, the assertion in the UT is run before the consumption of the event sent into the channel. I tried to remove the
launch { }
inside the
start()
function, but without it, the runBlocking coroutine of the UT is suspended on
presenter.start()
because of the
for
loop inside the
start()
function. Am I doing something really wrong here in the
start()
function or is this a bad design that is hard to unit test or am I simply missing a point somewhere ? Thx
g

gildor

05/24/2018, 11:27 AM
It looks wrong to just.call launch inside of suspend function without join
You actually start you launch and do not wait for result just return
It's actually not clear how you can test this function with current design
Instead you can wrap function to launch in tests os something similar to send events to channel and listen at the same time
p

pdegand

05/24/2018, 12:28 PM
Thx @gildor, i removed the
launch
in the
suspend fun start()
function, and I wrapped the call to
start()
in the unit test with
launch(Unconfined)
and now it's working great
l

louiscad

05/24/2018, 12:42 PM
It does not actually consumes the channel since you use a regular for loop that doesn't close the channel like
consumeEach
or wrapping with
consume
would do
2 Views