How to properly test infinite coroutine loop with delay

Viewed 471

I have a coroutine function that runs infinitely and makes an API call every 8 seconds. I am trying to test it but something feels wrong. Here is the code:

class RefreshStocksUseCaseImpl(
    private val dispatcherProvider: DispatcherProvider,
    private val stocksRepository: StocksRepository
) : RefreshStocksUseCase {

    override suspend fun invoke() {
        withContext(dispatcherProvider.io) {
            try {
                while (true) {
                    stocksRepository.refreshStocks()
                    delay(THRESHOLD)
                }
            } catch (t: Throwable) {
                // We could make some extra handling here.
                throw t
            }
        }
    }

    companion object {

        private const val THRESHOLD = 8_000L // 8 seconds
    }
}

My test looks like that:

@ExperimentalCoroutinesApi
class RefreshStocksUseCaseImplTest {

    private lateinit var useCase: RefreshStocksUseCase

    private val dispatcherProvider = TestDispatcherProvider()

    @MockK
    private lateinit var stocksRepository: StocksRepository

    @Before
    fun setup() {
        MockKAnnotations.init(this, relaxUnitFun = false)
        useCase = RefreshStocksUseCaseImpl(dispatcherProvider, stocksRepository)
    }

    @Test
    fun `refreshStocks is called again after threshold`() = dispatcherProvider.io.runBlockingTest {
        coEvery { stocksRepository.refreshStocks() } just runs

        val job = launch {
            useCase()
        }
        advanceTimeBy(8_000)

        job.cancel()
        coVerify(exactly = 2) { stocksRepository.refreshStocks() }
    }
}

Even though it passes, I feel that I am doing something wrong. I feel like pauseDispatcher should have played some role here... Any improvements are welcome.

0 Answers
Related