'viewModel unit test with flow
I'm trying to write a unit test for my viewModel and I haven't figure out how to do it. I am using kotlin flow and jetpack compose. In the viewModel, the function changes de value of a mutableState list but when I call it on the test I don't know how to retrieve the value.
below is my view model, repository, fake repository and the test I have so far. How can I do it?
@HiltViewModel
class MarvelViewModel @Inject constructor(
private val repository: MarvelRepository
) : ViewModel() {
val result: MutableState<List<Result>> = mutableStateOf(listOf())
fun searchCharacter(
name: String,
context: Context
) {
viewModelScope.launch {
val ts = System.currentTimeMillis().toString()
val md = MessageDigest.getInstance("MD5")
val input = ts + PRIVATE_KEY + PUBLIC_KEY
val hash = BigInteger(1, md.digest(input.toByteArray())).toString(16)
val offset = if (page.value == 1) 0 else PAGE_SIZE * page.value
repository.searchCharacter(
name = name,
limit = PAGE_SIZE,
offset = offset,
ts = ts,
apikey = PUBLIC_KEY,
hash = hash
).onEach { dataState ->
loading.value = dataState.loading
dataState.data?.let {
Log.d(DEBUG_TAG, it.toString())
if (it.data.total > PAGE_SIZE) {
val rest = it.data.total % PAGE_SIZE
numPages.value = (it.data.total + rest) / PAGE_SIZE
}
nameSearch.value = textSearch.value
result.value = it.data.results
pageNumberList.value = (1..numPages.value).toList()
}
dataState.error?.let {
Toast.makeText(context, "Falha ao carregar", Toast.LENGTH_SHORT).show()
}
}.launchIn(viewModelScope)
}
}
class MarvelRepositoryImpl @Inject constructor(
private val retrofitService: RetrofitService
) : MarvelRepository {
override suspend fun searchCharacter(
name: String,
limit: Int,
offset: Int,
ts: String,
apikey: String,
hash: String
): Flow<DataState<Response>> = flow {
try {
emit(DataState.loading())
val response = retrofitService.search(name, limit, offset, ts, apikey, hash)
emit(DataState.success(response))
} catch (e: Exception) {
emit(DataState.error<Response>(e.message ?: "Unknown Error"))
}
}
}
class FakeRepositoryImpl : MarvelRepository {
override suspend fun searchCharacter(
name: String,
limit: Int,
offset: Int,
ts: String,
apikey: String,
hash: String
): Flow<DataState<Response>> = flow {
emit(DataState.loading())
emit(DataState.success(response))
}
}
val response = Response(
data = Data(
count = 4, limit = 4, offset = 0, results = listOf(
Result(
description = "Wounded", id = 1009368, name = "Iron Man",
thumbnail = Thumbnail(
extension = "jpg",
path = "http://i.annihil.us/u/prod/marvel/i/mg/9/c0/527bb7b37ff55"
)
),
Result(
description = "", id = 1017320, name = "Iron Man (Iron Man 3 - The Official Game)",
thumbnail = Thumbnail(
extension = "jpg",
path = "http://i.annihil.us/u/prod/marvel/i/mg/9/03/5239c1408c936"
)
),
Result(
description = "", id = 1017294, name = "Iron Man (LEGO Marvel Super Heroes)",
thumbnail = Thumbnail(
extension = "jpg",
path = "http://i.annihil.us/u/prod/marvel/i/mg/6/90/5239c3cc8a259"
)
),
Result(
description = "", id = 1017310, name = "Iron Man (Marvel Heroes)",
thumbnail = Thumbnail(
extension = "jpg",
path = "http://i.annihil.us/u/prod/marvel/i/mg/9/40/5239be60a67da"
)
)
), total = 7
), status = "Ok"
)
@ExperimentalCoroutinesApi
class MarvelViewModelTest {
@get:Rule
var instantExecutorRule = InstantTaskExecutorRule()
@get:Rule
var mainCoroutineRule = MainCoroutineRule()
val context = mock(Context::class.java)
private lateinit var viewModel: MarvelViewModel
private lateinit var repository: FakeRepositoryImpl
@Before
fun setup(){
repository = FakeRepositoryImpl()
viewModel = MarvelViewModel(repository)
}
@Test
fun `should return a flow of response`() = runBlockingTest {
viewModel.searchCharacter("iron man", context)
}
}
Solution 1:[1]
coroutineRule.runBlockingTest block flow until finish FakeRepositoryImpl
you could use
@Test
fun success() = coroutineRule.runBlockingTest {
//when
viewModel.searchCharacter("iron man", context)
//verify
assertEquals(response.data.results, searchViewModel.result)
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Emmanuel Montt |