Skip to content

Commit

Permalink
tests
Browse files Browse the repository at this point in the history
  • Loading branch information
RubyLichtenstein committed Oct 12, 2023
1 parent 02d67f6 commit 41cbecb
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ class ImagesRepositoryImplTest {
class FakeDogBreedApi : BreedImagesApi {

// Default behavior is to return a successful empty list.
var getBreedImagesMock: suspend (String) -> Result<List<String>> =
{ breed -> Result.success(emptyList()) }
var getBreedImagesMock: suspend (String) -> List<String> =
{ breed -> emptyList() }

override suspend fun getBreedImages(breed: String): Result<List<String>> {
override suspend fun getBreedImages(breed: String): List<String> {
return getBreedImagesMock(breed)
}
}
Expand Down Expand Up @@ -60,7 +60,7 @@ class ImagesRepositoryImplTest {
fun `getImagesByBreed fetches from remote when local is empty and stores locally`() = runTest {
// Given
fakeApi.getBreedImagesMock = { breed ->
Result.success(listOf("url1", "url2"))
listOf("url1", "url2")
}

// Act & Assert
Expand All @@ -78,7 +78,7 @@ class ImagesRepositoryImplTest {
fun `getImagesByBreed updates local data when remote data is fetched`() = runTest {
// Given
fakeApi.getBreedImagesMock = { breed ->
Result.success(listOf("url3", "url4"))
listOf("url3", "url4")
}

val localData = DogImageDataEntity("breedName", "breedKey", false, "localUrl")
Expand All @@ -100,7 +100,7 @@ class ImagesRepositoryImplTest {
fun `getImagesByBreed fetches from remote when local is empty`() = runTest {
// Given
fakeApi.getBreedImagesMock = { breed ->
Result.success(listOf("url5", "url6"))
listOf("url5", "url6")
}

// Act & Assert
Expand All @@ -117,7 +117,7 @@ class ImagesRepositoryImplTest {
runTest {
// Given
fakeApi.getBreedImagesMock = { breed ->
Result.success(listOf("url7", "url8"))
listOf("url7", "url8")
}

val localData = DogImageDataEntity("breedName", "breedKey", false, "localUrl")
Expand All @@ -139,7 +139,7 @@ class ImagesRepositoryImplTest {
fun `getImagesByBreed returns error when remote fetch fails`() = runTest {
// Given
fakeApi.getBreedImagesMock = { breed ->
Result.failure(Exception("API failed"))
error("API failed")
}

// Act & Assert
Expand Down
14 changes: 7 additions & 7 deletions ui/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,19 @@ dependencies {
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")

implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2")
implementation("androidx.navigation:navigation-compose:2.7.2")
implementation("androidx.navigation:navigation-compose:2.7.4")
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.7.0-alpha02")
implementation("androidx.compose.material3:material3:1.2.0-alpha07")
implementation("androidx.compose.material:material-icons-extended:1.5.1")
implementation("androidx.compose.material3:material3:1.2.0-alpha09")
implementation("androidx.compose.material:material-icons-extended:1.5.3")
implementation("androidx.hilt:hilt-navigation-compose:1.0.0")
implementation("io.coil-kt:coil-compose:2.4.0")

implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")

androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
testImplementation("org.junit.jupiter:junit-jupiter:$junitVersion")
testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junitVersion")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class BreedsViewModel @Inject constructor(
.asUiState()
.stateIn(
viewModelScope,
SharingStarted.Lazily,
SharingStarted.WhileSubscribed(5_000),
UiState.Loading
)
}
32 changes: 15 additions & 17 deletions ui/src/main/java/com/rubylichtenstein/ui/common/UiState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,23 @@ sealed interface UiState<out T> {

fun <T> Flow<T>.asUiState(
errorMessage: String? = null
): Flow<UiState<T>> {
return this
.map<T, UiState<T>> {
UiState.Success(it)
}
.catch { emit(UiState.Error(errorMessage ?: it.message)) }
}
): Flow<UiState<T>> =
map<T, UiState<T>> {
UiState.Success(it)
}.catch {
emit(UiState.Error(errorMessage ?: it.message))
}

fun <T> Flow<List<T>>.asUiState(
emptyMessage: String? = null,
errorMessage: String? = null
): Flow<UiState<List<T>>> {
return this
.map {
if (it.isEmpty()) {
UiState.Empty(emptyMessage)
} else {
UiState.Success(it)
}
): Flow<UiState<List<T>>> =
map {
if (it.isEmpty()) {
UiState.Empty(emptyMessage)
} else {
UiState.Success(it)
}
.catch { emit(UiState.Error(errorMessage ?: it.message)) }
}
}.catch {
emit(UiState.Error(errorMessage ?: it.message))
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class FavoritesViewModel @Inject constructor(
it.size
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(),
started = SharingStarted.WhileSubscribed(5_000),
initialValue = 0
)

Expand Down
17 changes: 2 additions & 15 deletions ui/src/test/java/com/rubylichtenstein/ui/common/UiStateTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,6 @@ import java.util.Locale

class UiStateTest {

@Test
fun `mapSuccess returns Loading when source is Loading`() = runTest {
val source: UiState<String> = UiState.Loading
val result = source.mapSuccess { it.uppercase(Locale.getDefault()) }
assertTrue(result is UiState.Loading)
}

@Test
fun `mapSuccess transforms Success data`() = runTest {
val source: UiState<String> = UiState.Success("test")
Expand All @@ -32,23 +25,17 @@ class UiStateTest {
assertTrue(result is UiState.Error && result.message == error)
}

@Test
fun `asAsyncResult emits Loading at start`() = runTest {
val flow = flowOf("data").asUiState().toList()
assertTrue(flow.first() is UiState.Loading)
}

@Test
fun `asAsyncResult emits Success with data`() = runTest {
val flow = flowOf("data").asUiState().toList()
val result = flow.drop(1).first()
val result = flow.first()
assertTrue(result is UiState.Success && result.data == "data")
}

@Test
fun `asAsyncResult emits Error on exception`() = runTest {
val flow = flow<String> { throw Exception("Error") }.asUiState().toList()
val result = flow.drop(1).first()
val result = flow.first()
assertTrue(result is UiState.Error && result?.message == "Error")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,34 +46,6 @@ class FavoritesPresenterTest {
}
}

// @Test
// fun `FavoritesPresenter returns empty dog images on non-existent breed selection`() = runTest {
// val breedToSelect = ChipInfo("Husky1", selected = true)
// val eventFlow = MutableSharedFlow<Event>()
// val favoriteImagesFlow = flowOf(
// listOf(
// DogImageEntity(
// "Husky1",
// "Husky",
// true,
// "husky",
// )
// )
// )
//
// moleculeFlow(RecompositionMode.Immediate) {
// FavoritesPresenter(eventFlow, favoriteImagesFlow)
// }.test {
// eventFlow.emit(Event.ToggleSelectedBreed(breedToSelect))
// assertTrue(awaitItem() is AsyncResult.Loading)
// val result = awaitItem()
// println(result)
// assertTrue(result is AsyncResult.Success)
// assertTrue((result as AsyncResult.Success).data.dogImages.isEmpty())
// cancelAndIgnoreRemainingEvents()
// }
// }

@Test
fun `FavoritesPresenter returns success state with dog images`() = runTest {
val eventFlow = MutableSharedFlow<Event>()
Expand Down Expand Up @@ -148,8 +120,8 @@ class FavoritesPresenterTest {
FavoritesPresenter(eventFlow, favoriteImagesFlow)
}.test {
assertTrue(awaitItem() is UiState.Loading)
val result = awaitItem() as UiState.Success
assertTrue(result.data.dogImages.isEmpty())
//asser type is Empty
assertTrue(awaitItem() is UiState.Empty)
cancel()
}
}
Expand Down

0 comments on commit 41cbecb

Please sign in to comment.