Search code examples
androidkotlinkotlin-coroutineskotlin-flow

java.util.NoSuchElementException: Flow is empty


I'm trying to test this repository using a unit test with JUnit 4

class AppRepository @Inject constructor(
    private val networkHelper: NetworkHelper,
    private val weatherMapper: WeatherMapper,
    private val cacheHelper: CacheHelper
) : Repository {
    override fun fetchWeatherInfo(lat: Double, lng: Double): Flow<AppResult<Weather>> {
        return networkHelper.getWeatherInfo(lat, lng).map {
            when(it){
                is AppResult.Error -> AppResult.Error(it.errorMessage)
                is AppResult.Success -> AppResult.Success(weatherMapper.map(it.data))
            }
        }
    }
}

So I've made a unit test class like this using coroutine dispatcher and mock some interfaces for repository

@ExperimentalCoroutinesApi
@RunWith(JUnit4::class)
class AppRepositoryTest{
    private val dispatcher = TestCoroutineDispatcher()
    @Mock
    private lateinit var networkHelper: NetworkHelper
    @Mock
    private lateinit var cacheHelper: CacheHelper
    private val mapper=WeatherMapper()
    private lateinit var repository: AppRepository
    @Before
    fun setup(){
        MockitoAnnotations.openMocks(this)
        repository= AppRepository(networkHelper,mapper,cacheHelper)
    }
    @Test
    fun`check if weather info returned failed`(){
       dispatcher.runBlockingTest {
           val expected:AppResult<Weather> = AppResult.Error("Can't load weather info")
           `when`(networkHelper.getWeatherInfo(1.0,1.0)).thenReturn(
               flow { AppResult.Error("Can't load weather info") }
           )
          val result= repository.fetchWeatherInfo(1.0,1.0).single()
          assertEquals(expected,result)
       }
    }
}

I want to test a failed case for the current repository function but the failed crashed due to this error

Flow is empty
java.util.NoSuchElementException: Flow is empty
    at kotlinx.coroutines.flow.FlowKt__ReduceKt.single(Reduce.kt:62)
    at kotlinx.coroutines.flow.FlowKt.single(Unknown Source)
    at com.isma3il.photoweatherapp.data.repositories.AppRepositoryTest$check if weather info returned failed$1.invokeSuspend(AppRepositoryTest.kt:73)
    at com.isma3il.photoweatherapp.data.repositories.AppRepositoryTest$check if weather info returned failed$1.invoke(AppRepositoryTest.kt)
    at com.isma3il.photoweatherapp.data.repositories.AppRepositoryTest$check if weather info returned failed$1.invoke(AppRepositoryTest.kt)

so how to fix this issue and how to use flow in testing?


Solution

  • I totally forget to emit data inside the flow builder like this

    `when`(networkHelper.getWeatherInfo(1.0,1.0)).thenReturn(
               flow { emit(AppResult.Error("Can't load weather info")) }
           )
    

    and that is works for me.