How can I best go about unit testing flows that are collected in a class’s init function?
The only solution I’ve come up with so far requires hard-coded delays.
Consider a sample implementation of a NotificationService
and a UserSession
that uses said service.
class NotificationService {
private val notificationFlow = MutableSharedFlow<Notification>()
suspend fun notify(notification: Notification) { notificationFlow.emit(notification) }
fun subscribe() = notificationFlow.asSharedFlow()
}
class UserSession(
coroutineContext: CoroutineContext,
private val notificationService: NotificationService
) {
/* ... user related fields ... */
private val scope = CoroutineScope(coroutineContext)
init {
scope.launch {
notificationService.subscribe().collect { /* Handle notifications */ }
}
}
/* ... user related functions ... */
}
When attempting to write a basic unit test, similar to:
@Test
fun `Can instantiate class`() = runTest {
val notificationService = spy(NotificationService())
val unit = unit(testScheduler, notificationService)
verify(notificationService).subscribe()
}
Then the test will become flaky, as occationally, the init
-function will not have time to start collecting before the unit test verifies that the function NotificationService#subscribe()
has been called.
How can I best wait until unit
has completed it’s instantiation?