would someone be able to show me how to make the getMovies function in this viewModel testable? I can't get the unit tests to await the coroutines properly..
(1) I'm pretty sure I have to create a test-CoroutineScope and a normal lifeCycle-CoroutineScope, as seen in this Medium Article.
(2) Once the scope definitions are made, I'm also unsure how to tell getMovies() which scope it should be using given a normal app context or a test context.
enum class MovieApiStatus { LOADING, ERROR, DONE }
class MovieListViewModel : ViewModel() {
var pageCount = 1
private val _status = MutableLiveData<MovieApiStatus>()
val status: LiveData<MovieApiStatus>
get() = _status
private val _movieList = MutableLiveData<List<Movie>>()
val movieList: LiveData<List<Movie>>
get() = _movieList
// allows easy update of the value of the MutableLiveData
private var viewModelJob = Job()
// the Coroutine runs using the Main (UI) dispatcher
private val coroutineScope = CoroutineScope(
viewModelJob + Dispatchers.Main
)
init {
Log.d("list", "in init")
getMovies(pageCount)
}
fun getMovies(pageNumber: Int) {
coroutineScope.launch {
val getMoviesDeferred =
MovieApi.retrofitService.getMoviesAsync(page = pageNumber)
try {
_status.value = MovieApiStatus.LOADING
val responseObject = getMoviesDeferred.await()
_status.value = MovieApiStatus.DONE
............
} catch (e: Exception) {
_status.value = MovieApiStatus.ERROR
................
}
}
pageCount = pageNumber.inc()
}
...
}
it uses this API service...
package com.example.themovieapp.network
import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import kotlinx.coroutines.Deferred
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.http.GET
import retrofit2.http.Query
private const val BASE_URL = "https://api.themoviedb.org/3/"
private const val API_key = ""
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
private val retrofit = Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.baseUrl(BASE_URL)
.build()
interface MovieApiService{
//https://developers.themoviedb.org/3/movies/get-top-rated-movies
//https://square.github.io/retrofit/2.x/retrofit/index.html?retrofit2/http/Query.html
@GET("movie/top_rated")
fun getMoviesAsync(
@Query("api_key") apiKey: String = API_key,
@Query("language") language: String = "en-US",
@Query("page") page: Int
): Deferred<ResponseObject>
}
/*
Because this call is expensive, and the app only needs
one Retrofit service instance, you expose the service to the rest of the app using
a public object called MovieApi, and lazily initialize the Retrofit service there
*/
object MovieApi {
val retrofitService: MovieApiService by lazy {
retrofit.create(MovieApiService::class.java)
}
}
I'm simply trying to create a test which asserts the liveData 'status' is DONE after the function.
Here is the Project Repository