I'm assuming you can't or won't rewrite the code you are writing to use coroutines. In that case, Pablisco offered great ideas here. The one I liked the best was using a queue:
// You create a sync queue
val queue = SynchronousQueue<String>() // Or the type of 'fetch2Docs'
// fetchTwoDocs runs async so it will return eventually
queue.put(fetchTwoDocs())
// queue.take() will wait until there is a value in the queue
assertThat(queue.take(), equalTo("expected value"))
Here an extra example on how to use this in an hypothetical async callback:
val queue = SynchronousQueue<String>()
asyncFunctionThatReturnsWithCallback(someParam) { callbackParam ->
queue.put(callbackParam)
}
assertTrue(queue.take())