what are the rules for how coroutineContext is loo...
# coroutines
p
what are the rules for how coroutineContext is looked up? I’m finding it a little bit surprising to say the least. I’ve got a test (using mockk.io) structured roughly like this:
Copy code
@Test fun `some particular invariant holds true`() = runBlockingTest {
    coEvery { someSuspendingFunction() } coAnswers { 
        val dispatcher = coroutineContext[CoroutineDispatcher]
        ....
    }
    ....
}
No matter which CoroutineDispatcher someSuspendingFunction() was called on,
dispatcher
in this code seems to end up being the test dispatcher created by runBlockingTest. If, however, I structure it like this:
Copy code
private suspend fun mockImplementation() {
    val dispatcher = coroutineContext[CoroutineDispatcher]
}

@Test fun `some particular invariant holds true`() = runBlockingTest {
    coEvery { someSuspendingFunction() } coAnswers {
        mockImplementation()
    }
}
dispatcher
(in mockImplementation()) matches the dispatcher that someSuspendingFunction() was called on. IE… it looks an awful like the coAnswers block is running on that dispatcher, but
coroutineContext
specifically inside that block is reporting something different. Put differently --- coroutineContext seems to be returning the context from the enclosing lexical scope, rather than the context of the actual running coroutine. Is that expected?
Context: I’m trying to write a test that asserts which dispatcher a piece of code is run on.
I recognize that accessing coroutineContext is not recommended, and that our tests may break as that API changes (and to be clear, we’re not doing it outside of these few tests).
I just wanna understand the semantics as they are.
Also, doing,
Copy code
@Test fun `some particular invariant holds true`() {
    coEvery { someSuspendingFunction() } coAnswers {
        val dispatcher = coroutineContext[CoroutineDispatcher]
        ...
    }
    runBlockingTest {
        ... rest of the test body ...
    }
}
fixes the test.
(ie, if the coAnswers block is defined outside of runBlockingTest {}, then its coroutineContext reflects reality)