From 182e3844d9b2ed5a572cd61a41bc161c152035b7 Mon Sep 17 00:00:00 2001 From: theophiluskibet Date: Mon, 3 Jun 2024 15:09:49 +0300 Subject: [PATCH] add tests for details view model --- .../details/screens/DetailsViewModelTest.kt | 63 +++++++++++++++++-- .../details/utils/FakeCaloreeRepository.kt | 44 ++++++++----- 2 files changed, 85 insertions(+), 22 deletions(-) diff --git a/feature/details/src/commonTest/kotlin/com/theophiluskibet/calorees/details/screens/DetailsViewModelTest.kt b/feature/details/src/commonTest/kotlin/com/theophiluskibet/calorees/details/screens/DetailsViewModelTest.kt index 5da0605..11dbe67 100644 --- a/feature/details/src/commonTest/kotlin/com/theophiluskibet/calorees/details/screens/DetailsViewModelTest.kt +++ b/feature/details/src/commonTest/kotlin/com/theophiluskibet/calorees/details/screens/DetailsViewModelTest.kt @@ -1,8 +1,13 @@ package com.theophiluskibet.calorees.details.screens import com.theophilus.kibet.caloree.data.sources.CaloreeRepositoryImpl +import com.theophiluskibet.calorees.details.utils.DetailsUiState import com.theophiluskibet.calorees.details.utils.FakeCaloreeRepository +import com.theophiluskibet.calorees.details.utils.searchData import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain @@ -10,6 +15,7 @@ import kotlin.test.AfterTest import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertTrue class DetailsViewModelTest { @@ -18,7 +24,7 @@ class DetailsViewModelTest { @BeforeTest fun setup() { - Dispatchers.setMain(Dispatchers.Unconfined) + Dispatchers.setMain(StandardTestDispatcher()) detailsViewModel = DetailsViewModel(repository = repository) } @@ -28,9 +34,56 @@ class DetailsViewModelTest { } @Test - fun `sample test`() = runTest { - val data = repository.searchCalories("meat") - detailsViewModel.getCaloreeDetails("meat") - assertEquals("meat", data.first().name) + fun `given DetailsViewModel- initial details ui state is default`() = runTest { + assertEquals(detailsViewModel.caloreeUiState.value, DetailsUiState.Default) } + + @Test + fun `given string of food - when getCalireeDetails is invoked - then details ui state is loading`() = + runTest { + // given + val food = "rice" + + // when + detailsViewModel.getCaloreeDetails(food) + + // then + assertEquals(DetailsUiState.Loading, detailsViewModel.caloreeUiState.value) + } + + @Test + fun `given string of food - when getCalireeDetails is success - then details ui state is success with data`() = + runTest { + // given + val food = "rice" + + // when + detailsViewModel.getCaloreeDetails(food) + advanceUntilIdle() + + // then + assertEquals( + DetailsUiState.Success(data = searchData.first()), + detailsViewModel.caloreeUiState.value + ) + } + + @Test + fun `given string of food - when getCalireeDetails is error - then details ui state is error with message`() = + runTest { + // simulate error in the repository + repository.shouldThrowError = true + // given + val food = "rice" + + // when + detailsViewModel.getCaloreeDetails(food) + advanceUntilIdle() + + // then + assertEquals( + DetailsUiState.Error(errorMessage = "An error occured"), + detailsViewModel.caloreeUiState.value + ) + } } \ No newline at end of file diff --git a/feature/details/src/commonTest/kotlin/com/theophiluskibet/calorees/details/utils/FakeCaloreeRepository.kt b/feature/details/src/commonTest/kotlin/com/theophiluskibet/calorees/details/utils/FakeCaloreeRepository.kt index d0ed501..13b74d9 100644 --- a/feature/details/src/commonTest/kotlin/com/theophiluskibet/calorees/details/utils/FakeCaloreeRepository.kt +++ b/feature/details/src/commonTest/kotlin/com/theophiluskibet/calorees/details/utils/FakeCaloreeRepository.kt @@ -5,23 +5,16 @@ import com.theophilus.kibet.caloree.data.sources.CaloreeRepository import kotlinx.coroutines.flow.Flow class FakeCaloreeRepository : CaloreeRepository { + var shouldThrowError = false override suspend fun searchCalories(query: String): List { - return listOf( - Caloree( - name = "meat", - calories = 20.0, - carbohydratesTotalGrams = 20.0, - cholesterolMilliGrams = 100, - fatSaturatedGrams = 30.0, - fatTotalGrams = 44.0, - fiberGrams = 30.0, - potassiumMilliGrams = 261, - proteinGrams = 104.0, - servingSizeGrams = 100.0, - sodiumMilliGrams = 127, - sugarGrams = 68.0, - ) - ) + if (shouldThrowError) { + throw RuntimeException("An error occured") + } + return searchData + } + + fun simulateError(): List { + throw Throwable(message = "Error occured") } override suspend fun getSavedCalories(): Flow> { @@ -31,4 +24,21 @@ class FakeCaloreeRepository : CaloreeRepository { override suspend fun getCalorieDetails(food: String): Flow { TODO("Not yet implemented") } -} \ No newline at end of file +} + +val searchData = listOf( + Caloree( + name = "meat", + calories = 20.0, + carbohydratesTotalGrams = 20.0, + cholesterolMilliGrams = 100, + fatSaturatedGrams = 30.0, + fatTotalGrams = 44.0, + fiberGrams = 30.0, + potassiumMilliGrams = 261, + proteinGrams = 104.0, + servingSizeGrams = 100.0, + sodiumMilliGrams = 127, + sugarGrams = 68.0, + ) +) \ No newline at end of file