https://kotlinlang.org logo
Title
a

abbic

05/21/2023, 8:48 AM
Hi, im trying to write some tests around some code that delays before taking an action. however, delays are skipped when using
runTest
and its making testing the timeout impossible. am i missing something? im trying to use
advanceTimeBy
to maneuver around this delay for tests but it seems useless as the delays are just skipped
c

CLOVIS

05/21/2023, 9:17 AM
What is the timeout for? How does the system behave differently depending on whether the timeout finished or not?
a

abbic

05/21/2023, 9:19 AM
a lamda is run if the timeout completes
and the timeout completes if a flow doesn't emit in that time window
fun <T: Any> Flow<T>.ifDelayed(timeMillis: Long, block: () -> Unit): Flow<T> = channelFlow {
     val delayJob = launch {
         delay(timeMillis)
         block()
     }
 
     collect {
         delayJob.cancelAndJoin()
         send(it)
     }
 }
may not be correct, found an answer on stackoverflow that I'm still working to adapt and understand, and testing it properly is a part of that process
c

CLOVIS

05/21/2023, 9:49 AM
How I would do it:
@Test
fun lambdaIsNotCalledIfTimeoutDidntEnd() = runTest {
    var called = false
    flow {
        delay(100)
        emit(Unit)
    }.ifDelayed(1000) {
        called = true
    }.collect()
    assertFalse(called)
}

@Test
fun lambdaIsCalledIfTimeoutEnds() = runTest {
    var called = false
    flow {
        delay(5000)
        emit(Unit)
    }.ifDelayed(1000) {
        called = true
    }.collect()
    assertTrue(called)
}
a

abbic

05/21/2023, 10:52 AM
ooh brilliant
the thing for me here is understanding advanceTimeBy is useless for testing delays
c

CLOVIS

05/21/2023, 2:05 PM
It's not useless, it's just that what you want to test is whether the lambda is called or not. You don't really care about the control of time at all
In general, I recommend testing the effect of things rather than the things themselves. It's called black box testing, if you want to read more about it