I wrote a very simple slowdown function that can be used to slow down a response without blocking
suspend inline fun <T> slowdown(duration: Duration, block: () -> T): T {
var result: T
val timeTaken = measureTime {
result = block()
}
delay(duration - timeTaken)
return result
}
running it inside a main works correctly
fun main() = runBlocking {
val timeTaken1 = measureTime {
slowdown(2.seconds) {
delay(1000)
}
}
val timeTaken2 = measureTime {
slowdown(2.seconds) {
delay(4000)
}
}
println(timeTaken1) // 2.008962891s
println(timeTaken2) // 4.000145711s
}
Now I want to write a test case that will test the slowdown, but without actually taking 2 seconds or 4 seconds
@Test
@ExperimentalCoroutinesApi
fun `ensure execution takes N seconds when operation takes N-t time`() = runTest {
val timeTaken1 = measureTime {
slowdown(2.seconds) {
delay(1000)
}
}
val timeTaken2 = measureTime {
slowdown(2.seconds) {
delay(4000)
}
}
println("========")
println(timeTaken1) // 9.472240ms
println(timeTaken2) // 131.839us
println("========")
}
I'm assuming measureTime doesn't play nice with runTest
, but works great with delay
If I replace delay with Thread.sleep in the test
val timeTaken1 = measureTime {
slowdown(2.seconds) {
Thread.sleep(1000)
}
}
val timeTaken2 = measureTime {
slowdown(2.seconds) {
Thread.sleep(4000)
}
}
then it prints out
========
1.008311216s
4.000221902s
========
delay(1000)
happens instantly under runTest, but measureTime also measures it as instantly instead of being offset by 1 second.
I thought I could hack it using advanceTimeBy()
, but it doesn't seem to affect measureTime.
Changing runTest
to runBlocking
works correctly, but it also slows down the tests to 2 and 4 seconds respectively.
Is there a measureTime that plays nicely with runTest
and works under normal runBlocking
?
CodePudding user response:
suspend fun <T> slowdown(duration: Duration, block: suspend () -> T): T = coroutineScope {
launch { delay(duration) }
block()
}
@Test
@ExperimentalCoroutinesApi
fun `ensure execution takes N seconds when execution faster than N`() = runTest {
val currentTime1 = currentTime
slowdown(2.seconds) {
delay(1.seconds)
}
val currentTime2 = currentTime
assertEquals(2000, currentTime2 - currentTime1)
}
@Test
@ExperimentalCoroutinesApi
fun `ensure execution takes more than N seconds when execution slower than N`() = runTest {
val currentTime1 = currentTime
slowdown(1.seconds) {
delay(2.seconds)
}
val currentTime2 = currentTime
assertEquals(2000, currentTime2 - currentTime1)
}