https://kotlinlang.org logo
#coroutines
Title
# coroutines
f

fjoglar

10/19/2023, 9:52 PM
👋 Hello!! I'm struggling to test some behaviour with flows. Maybe someone here can help me 😄 This is my test:
Copy code
@OptIn(ExperimentalCoroutinesApi::class)
class EventRepositoryTest {

    private val eventService = EventServiceStub()
    private val eventCache = EventCacheStub()

    private val eventRepository = EventRepository(
        localCache = eventCache,
        remoteService = eventService,
    )

    @Test
    fun test_deliversRemoteEvents_onNonValidCache() = runTest {
        val remoteEvents = makeEvents(1)

        val receivedEvents = mutableListOf<List<Event>>()
        backgroundScope.launch(UnconfinedTestDispatcher()) {
            eventRepository.load(anyFilter().toList(receivedEvents)
        }

        eventService.succeedsWithEvents(remoteEvents)
        eventCache.failsWithNonValidCache()

        assertEquals(remoteEvents, receivedEvents.first())
    }

    // region Helpers

    private class EventServiceStub : EventService {
        private var result: Result<List<Event>>? = null

        override suspend fun load(filter: EventFilter): Result<List<Event>> {
            return result!!
        }

        fun succeedsWithEvents(remoteEvents: List<Event>) {
            result = Result.success(remoteEvents)
        }
    }

    private class EventCacheStub : EventCache {

        private val flow = MutableSharedFlow<List<Event>?>()

        override fun load(filter: EventFilter): Flow<List<Event>?> = flow

        suspend fun succeedsWithEvents(events: List<Event>?) {
            flow.emit(events)
        }

        suspend fun failsWithNonValidCache() {
            flow.emit(null)
        }

        override suspend fun save(events: List<Event>, filter: EventFilter) {
            flow.emit(events)
        }
    }

    // endregion
}
Here I am expecting to receive
remoteEvents
when the
localCache
is not valid, which is when it returns
null
. Actually, EventCacheStub emits a null value when calling
failsWithNonValidCache
but it does not emit nothing and completes after calling the
save
method from the repository implementation. Here is my repository implementation:
Copy code
class EventRepository(
    private val localCache: EventCache,
    private val remoteService: EventService,
) : EventLoader {

    override fun load(filter: EventFilter): Flow<List<Event>> {
        return localCache.load(filter)
            .onEach {
                if (it == null) {
                    remoteService.load(filter).onSuccess { localCache.save(it, filter)}
                }
            }
            .filterNotNull()
    }
}
Thanks gratitude thank you
I've actually found out that the second emit, the one on:
Copy code
override suspend fun save(events: List<Event>, filter: EventFilter) {
            flow.emit(events)
        }
Is failing because of:
Copy code
kotlinx.coroutines.JobCancellationException: Job was cancelled; job=ReportingSupervisorJob{Cancelling}@54dcfa5a
Any hint on how can I fix it?