From 92a07bb2701ecb74b3ca53402ba1d4abb19c11c0 Mon Sep 17 00:00:00 2001 From: Pell Date: Tue, 29 Apr 2025 09:37:17 +0200 Subject: [PATCH 01/15] Changed some class visibility --- ...spatcherRules.kt => MainDispatcherRule.kt} | 0 .../data/mother/RandomUsersResponseMother.kt | 24 +++++++++---------- .../random/users/domain/mother/UserMother.kt | 10 ++++---- .../random/users/users/mother/UserMother.kt | 8 +++---- 4 files changed, 21 insertions(+), 21 deletions(-) rename core/test/src/main/kotlin/com/random/users/test/rules/{DispatcherRules.kt => MainDispatcherRule.kt} (100%) diff --git a/core/test/src/main/kotlin/com/random/users/test/rules/DispatcherRules.kt b/core/test/src/main/kotlin/com/random/users/test/rules/MainDispatcherRule.kt similarity index 100% rename from core/test/src/main/kotlin/com/random/users/test/rules/DispatcherRules.kt rename to core/test/src/main/kotlin/com/random/users/test/rules/MainDispatcherRule.kt diff --git a/data/src/test/kotlin/com/random/users/data/mother/RandomUsersResponseMother.kt b/data/src/test/kotlin/com/random/users/data/mother/RandomUsersResponseMother.kt index e9fd638..22b0d32 100644 --- a/data/src/test/kotlin/com/random/users/data/mother/RandomUsersResponseMother.kt +++ b/data/src/test/kotlin/com/random/users/data/mother/RandomUsersResponseMother.kt @@ -13,14 +13,14 @@ import com.random.users.api.model.StreetDto import com.random.users.api.model.TimezoneDto import com.random.users.api.model.UserDto -object RandomUsersResponseMother { +internal object RandomUsersResponseMother { fun createModel( results: List = listOf(UserDtoMother.createModel()), info: ResponseInfoDto = ResponseInfoDtoMother.createModel(), ): RandomUserResponse = RandomUserResponse(results, info) } -object ResponseInfoDtoMother { +internal object ResponseInfoDtoMother { fun createModel( seed: String = "default-seed", results: Int = 10, @@ -35,7 +35,7 @@ object ResponseInfoDtoMother { ) } -object UserDtoMother { +internal object UserDtoMother { fun createModel( gender: String = "male", name: NameDto = NameDtoMother.createModel(), @@ -66,7 +66,7 @@ object UserDtoMother { ) } -object NameDtoMother { +private object NameDtoMother { fun createModel( title: String = "Mr", first: String = "John", @@ -74,7 +74,7 @@ object NameDtoMother { ): NameDto = NameDto(title, first, last) } -object LocationDtoMother { +private object LocationDtoMother { fun createModel( street: StreetDto = StreetDtoMother.createModel(), city: String = "New York", @@ -86,28 +86,28 @@ object LocationDtoMother { ): LocationDto = LocationDto(street, city, state, country, postcode, coordinates, timezone) } -object StreetDtoMother { +private object StreetDtoMother { fun createModel( number: Int = 123, name: String = "Main Street", ): StreetDto = StreetDto(number, name) } -object CoordinatesDtoMother { +private object CoordinatesDtoMother { fun createModel( latitude: String = "40.7128", longitude: String = "-74.0060", ): CoordinatesDto = CoordinatesDto(latitude, longitude) } -object TimezoneDtoMother { +private object TimezoneDtoMother { fun createModel( offset: String = "-05:00", description: String = "Eastern Time (US & Canada)", ): TimezoneDto = TimezoneDto(offset, description) } -object LoginDtoMother { +private object LoginDtoMother { fun createModel( uuid: String = "mock-uuid", username: String = "johndoe", @@ -119,21 +119,21 @@ object LoginDtoMother { ): LoginDto = LoginDto(uuid, username, password, salt, md5, sha1, sha256) } -object DateInfoDtoMother { +private object DateInfoDtoMother { fun createModel( date: String = "2000-01-01T00:00:00Z", age: Int = 21, ): DateInfoDto = DateInfoDto(date, age) } -object IdDtoMother { +private object IdDtoMother { fun createModel( name: String = "SSN", value: String = "123-45-6789", ): IdDto = IdDto(name, value) } -object PictureDtoMother { +private object PictureDtoMother { fun createModel( large: String = "https://example.com/large.jpg", medium: String = "https://example.com/medium.jpg", diff --git a/domain/src/test/kotlin/com/random/users/domain/mother/UserMother.kt b/domain/src/test/kotlin/com/random/users/domain/mother/UserMother.kt index de74db6..5060f5e 100644 --- a/domain/src/test/kotlin/com/random/users/domain/mother/UserMother.kt +++ b/domain/src/test/kotlin/com/random/users/domain/mother/UserMother.kt @@ -6,7 +6,7 @@ import com.random.users.domain.models.UserName import com.random.users.domain.models.UserPicture import com.random.users.domain.models.UserStreet -object UserMother { +internal object UserMother { fun createModel( uuid: String = "mock-uuid", name: UserName = createUserName(), @@ -26,23 +26,23 @@ object UserMother { picture = picture, ) - fun createUserName( + private fun createUserName( first: String = "John", last: String = "Doe", ): UserName = UserName(first, last) - fun createUserLocation( + private fun createUserLocation( street: UserStreet = createUserStreet(), city: String = "Madrid", state: String = "Madrid", ): UserLocation = UserLocation(street, city, state) - fun createUserStreet( + private fun createUserStreet( number: Int = 123, name: String = "Calle Mayor", ): UserStreet = UserStreet(number, name) - fun createUserPicture( + private fun createUserPicture( medium: String = "https://example.com/medium.jpg", thumbnail: String = "https://example.com/thumbnail.jpg", ): UserPicture = UserPicture(medium, thumbnail) diff --git a/presentation/users/src/test/kotlin/com/random/users/users/mother/UserMother.kt b/presentation/users/src/test/kotlin/com/random/users/users/mother/UserMother.kt index 7be98bc..43762a5 100644 --- a/presentation/users/src/test/kotlin/com/random/users/users/mother/UserMother.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/mother/UserMother.kt @@ -26,23 +26,23 @@ internal object UserMother { picture = picture, ) - fun createUserName( + private fun createUserName( first: String = "John", last: String = "Doe", ): UserName = UserName(first, last) - fun createUserLocation( + private fun createUserLocation( street: UserStreet = createUserStreet(), city: String = "Madrid", state: String = "Madrid", ): UserLocation = UserLocation(street, city, state) - fun createUserStreet( + private fun createUserStreet( number: Int = 123, name: String = "Calle Mayor", ): UserStreet = UserStreet(number, name) - fun createUserPicture( + private fun createUserPicture( medium: String = "https://example.com/medium.jpg", thumbnail: String = "https://example.com/thumbnail.jpg", ): UserPicture = UserPicture(medium, thumbnail) From b9366074fd170526c0db51c99fd3a94975831ef1 Mon Sep 17 00:00:00 2001 From: Pell Date: Tue, 29 Apr 2025 09:37:43 +0200 Subject: [PATCH 02/15] Added take request assertion --- .../UsersViewModelIntegrationTest.kt | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelIntegrationTest.kt b/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelIntegrationTest.kt index 333fa6b..cbebb1d 100644 --- a/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelIntegrationTest.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelIntegrationTest.kt @@ -6,8 +6,8 @@ import com.random.users.domain.usecase.DeleteUserUseCase import com.random.users.domain.usecase.GetUserListUseCase import com.random.users.test.model.getUserListResponsePage1Json import com.random.users.test.rules.MainDispatcherRule -import com.random.users.users.contract.UsersErrorUiEventsState -import com.random.users.users.contract.UsersEvent +import com.random.users.users.contract.UsersErrorUiState +import com.random.users.users.contract.UsersUiEvent import com.random.users.users.contract.UsersScreenUiState import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest @@ -26,7 +26,6 @@ import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import javax.inject.Inject -import kotlin.getValue import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -76,7 +75,7 @@ internal class UsersViewModelIntegrationTest { initViewModel() mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody(getUserListResponsePage1Json)) - viewModel.handleEvent(UsersEvent.OnLoadUsers) + viewModel.handleEvent(UsersUiEvent.OnLoadUsers) runCurrent() viewModel.uiState.test { @@ -87,6 +86,10 @@ internal class UsersViewModelIntegrationTest { assertTrue(finalState.users.isNotEmpty()) expectNoEvents() } + + mockWebServer.takeRequest().requestUrl?.let { + assertEquals("0", it.queryParameter("page")) + } } @Test @@ -95,7 +98,7 @@ internal class UsersViewModelIntegrationTest { initViewModel() mockWebServer.enqueue(MockResponse().setResponseCode(500)) - viewModel.handleEvent(UsersEvent.OnLoadUsers) + viewModel.handleEvent(UsersUiEvent.OnLoadUsers) runCurrent() viewModel.uiState.test { @@ -107,7 +110,7 @@ internal class UsersViewModelIntegrationTest { } viewModel.uiEventsState.test { - assertEquals(UsersErrorUiEventsState.LoadUsersError, awaitItem()) + assertEquals(UsersErrorUiState.LoadUsersError, awaitItem()) expectNoEvents() } } @@ -118,12 +121,12 @@ internal class UsersViewModelIntegrationTest { initViewModel() mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody(getUserListResponsePage1Json)) - viewModel.handleEvent(UsersEvent.OnLoadUsers) + viewModel.handleEvent(UsersUiEvent.OnLoadUsers) runCurrent() viewModel.uiState.test { skipItems(2) - viewModel.handleEvent(UsersEvent.OnFilterUsers("Jos")) + viewModel.handleEvent(UsersUiEvent.OnFilterUsers("Jos")) runCurrent() val newState = awaitItem() @@ -140,7 +143,7 @@ internal class UsersViewModelIntegrationTest { initViewModel() mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody(getUserListResponsePage1Json)) - viewModel.handleEvent(UsersEvent.OnFilterUsers("")) + viewModel.handleEvent(UsersUiEvent.OnFilterUsers("")) runCurrent() viewModel.uiState.test { From fba54d8849163c70abf18db188ae1606032afd0b Mon Sep 17 00:00:00 2001 From: Pell Date: Tue, 29 Apr 2025 09:37:57 +0200 Subject: [PATCH 03/15] Class to interface in Ui errors --- .../users/users/contract/UsersScreenContract.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/presentation/users/src/main/kotlin/com/random/users/users/contract/UsersScreenContract.kt b/presentation/users/src/main/kotlin/com/random/users/users/contract/UsersScreenContract.kt index 33651bd..fa9112d 100644 --- a/presentation/users/src/main/kotlin/com/random/users/users/contract/UsersScreenContract.kt +++ b/presentation/users/src/main/kotlin/com/random/users/users/contract/UsersScreenContract.kt @@ -32,22 +32,22 @@ internal data class UserUiState( } } -internal sealed interface UsersEvent { - data object OnLoadUsers : UsersEvent +internal sealed interface UsersUiEvent { + data object OnLoadUsers : UsersUiEvent data class OnFilterUsers( val filterText: String, - ) : UsersEvent + ) : UsersUiEvent data class OnDeleteUser( val uuid: String, - ) : UsersEvent + ) : UsersUiEvent } -internal sealed class UsersErrorUiEventsState { - data object DeleteError : UsersErrorUiEventsState() +internal sealed interface UsersErrorUiState { + data object DeleteError : UsersErrorUiState - data object LoadUsersError : UsersErrorUiEventsState() + data object LoadUsersError : UsersErrorUiState - data object UnknownError : UsersErrorUiEventsState() + data object UnknownError : UsersErrorUiState } From 4a1e70957135cf570444d296f124a55cfa7cc317 Mon Sep 17 00:00:00 2001 From: Pell Date: Tue, 29 Apr 2025 09:38:11 +0200 Subject: [PATCH 04/15] Renamed events --- .../users/users/mapper/UsersErrorsMapper.kt | 8 ++++---- .../random/users/users/screen/UsersScreen.kt | 18 +++++++++--------- .../users/users/viewmodel/UsersViewModel.kt | 16 ++++++++-------- .../users/viewmodel/UsersViewModelUnitTest.kt | 8 ++++---- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/presentation/users/src/main/kotlin/com/random/users/users/mapper/UsersErrorsMapper.kt b/presentation/users/src/main/kotlin/com/random/users/users/mapper/UsersErrorsMapper.kt index 67ef8bd..a32efad 100644 --- a/presentation/users/src/main/kotlin/com/random/users/users/mapper/UsersErrorsMapper.kt +++ b/presentation/users/src/main/kotlin/com/random/users/users/mapper/UsersErrorsMapper.kt @@ -1,13 +1,13 @@ package com.random.users.users.mapper import com.random.users.domain.models.UsersErrors -import com.random.users.users.contract.UsersErrorUiEventsState +import com.random.users.users.contract.UsersErrorUiState internal object UsersErrorsMapper { fun UsersErrors.toUiError() = when (this) { - is UsersErrors.NetworkError -> UsersErrorUiEventsState.LoadUsersError - is UsersErrors.UserError -> UsersErrorUiEventsState.DeleteError - else -> UsersErrorUiEventsState.UnknownError + is UsersErrors.NetworkError -> UsersErrorUiState.LoadUsersError + is UsersErrors.UserError -> UsersErrorUiState.DeleteError + else -> UsersErrorUiState.UnknownError } } diff --git a/presentation/users/src/main/kotlin/com/random/users/users/screen/UsersScreen.kt b/presentation/users/src/main/kotlin/com/random/users/users/screen/UsersScreen.kt index 194d3f4..12c2386 100644 --- a/presentation/users/src/main/kotlin/com/random/users/users/screen/UsersScreen.kt +++ b/presentation/users/src/main/kotlin/com/random/users/users/screen/UsersScreen.kt @@ -24,8 +24,8 @@ import com.random.user.presentation.ui.theme.RandomUsersTheme import com.random.users.users.composable.UserList import com.random.users.users.composable.UserSearchView import com.random.users.users.contract.UserUiState -import com.random.users.users.contract.UsersErrorUiEventsState -import com.random.users.users.contract.UsersEvent +import com.random.users.users.contract.UsersErrorUiState +import com.random.users.users.contract.UsersUiEvent import com.random.users.users.contract.UsersScreenUiState import com.random.users.users.model.UserUiModel import com.random.users.users.navigation.UsersRoute @@ -45,9 +45,9 @@ internal fun UsersScreen( UsersContent( modifier = Modifier.padding(innerPadding), state = state, - onDeleteUser = { viewModel.handleEvent(UsersEvent.OnDeleteUser(uuid = it)) }, - onLoadUsers = { viewModel.handleEvent(UsersEvent.OnLoadUsers) }, - onFilterUsers = { viewModel.handleEvent(UsersEvent.OnFilterUsers(filterText = it)) }, + onDeleteUser = { viewModel.handleEvent(UsersUiEvent.OnDeleteUser(uuid = it)) }, + onLoadUsers = { viewModel.handleEvent(UsersUiEvent.OnLoadUsers) }, + onFilterUsers = { viewModel.handleEvent(UsersUiEvent.OnFilterUsers(filterText = it)) }, onUserClick = { navController.navigate(UsersRoute.UserDetail(user = it)) }, ) } @@ -81,7 +81,7 @@ private fun UsersContent( } @Composable -private fun HandleOneTimeEvents(uiEventsState: Flow) { +private fun HandleOneTimeEvents(uiEventsState: Flow) { val lifecycle = LocalLifecycleOwner.current.lifecycle val context = LocalContext.current LaunchedEffect(uiEventsState) { @@ -94,15 +94,15 @@ private fun HandleOneTimeEvents(uiEventsState: Flow) { } private fun showError( - state: UsersErrorUiEventsState, + state: UsersErrorUiState, context: Context, ) { when (state) { - is UsersErrorUiEventsState.DeleteError -> { + is UsersErrorUiState.DeleteError -> { Toast.makeText(context, "Error deleting user", Toast.LENGTH_SHORT).show() } - is UsersErrorUiEventsState.LoadUsersError -> { + is UsersErrorUiState.LoadUsersError -> { Toast.makeText(context, "Error loading users", Toast.LENGTH_SHORT).show() } diff --git a/presentation/users/src/main/kotlin/com/random/users/users/viewmodel/UsersViewModel.kt b/presentation/users/src/main/kotlin/com/random/users/users/viewmodel/UsersViewModel.kt index 3dff250..40f7ff3 100644 --- a/presentation/users/src/main/kotlin/com/random/users/users/viewmodel/UsersViewModel.kt +++ b/presentation/users/src/main/kotlin/com/random/users/users/viewmodel/UsersViewModel.kt @@ -5,8 +5,8 @@ import androidx.lifecycle.viewModelScope import com.random.users.domain.usecase.DeleteUserUseCase import com.random.users.domain.usecase.GetUserListUseCase import com.random.users.users.contract.UserUiState -import com.random.users.users.contract.UsersErrorUiEventsState -import com.random.users.users.contract.UsersEvent +import com.random.users.users.contract.UsersErrorUiState +import com.random.users.users.contract.UsersUiEvent import com.random.users.users.contract.UsersScreenUiState import com.random.users.users.mapper.UsersErrorsMapper.toUiError import com.random.users.users.mapper.toUiState @@ -32,23 +32,23 @@ internal class UsersViewModel UsersScreenUiState(), ) val uiState: StateFlow = _uiState - private val _uiEventsState = Channel(capacity = Channel.CONFLATED) - val uiEventsState: Flow = _uiEventsState.receiveAsFlow() + private val _uiEventsState = Channel(capacity = Channel.CONFLATED) + val uiEventsState: Flow = _uiEventsState.receiveAsFlow() private var currentPage: Int = 0 private var userList: List = emptyList() - fun handleEvent(event: UsersEvent) { + fun handleEvent(event: UsersUiEvent) { when (event) { - is UsersEvent.OnLoadUsers -> { + is UsersUiEvent.OnLoadUsers -> { loadUsers() } - is UsersEvent.OnDeleteUser -> { + is UsersUiEvent.OnDeleteUser -> { deleteUser(uuid = event.uuid) } - is UsersEvent.OnFilterUsers -> { + is UsersUiEvent.OnFilterUsers -> { filterUsers(event.filterText) } } diff --git a/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelUnitTest.kt b/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelUnitTest.kt index 8953630..bc8a68a 100644 --- a/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelUnitTest.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelUnitTest.kt @@ -6,8 +6,8 @@ import com.random.users.domain.models.UsersErrors import com.random.users.domain.usecase.DeleteUserUseCase import com.random.users.domain.usecase.GetUserListUseCase import com.random.users.test.rules.MainDispatcherRule -import com.random.users.users.contract.UsersErrorUiEventsState -import com.random.users.users.contract.UsersEvent +import com.random.users.users.contract.UsersErrorUiState +import com.random.users.users.contract.UsersUiEvent import com.random.users.users.contract.UsersScreenUiState import io.mockk.coEvery import io.mockk.coVerify @@ -37,7 +37,7 @@ internal class UsersViewModelUnitTest { runTest { coEvery { deleteUserUseCase("1") } returns UsersErrors.UserError.left() - viewModel.handleEvent(UsersEvent.OnDeleteUser("1")) + viewModel.handleEvent(UsersUiEvent.OnDeleteUser("1")) runCurrent() viewModel.uiState.test { @@ -46,7 +46,7 @@ internal class UsersViewModelUnitTest { } viewModel.uiEventsState.test { - assertEquals(UsersErrorUiEventsState.DeleteError, awaitItem()) + assertEquals(UsersErrorUiState.DeleteError, awaitItem()) expectNoEvents() } From 8647596dc317db96385eca7a34a97ffaa2d679d1 Mon Sep 17 00:00:00 2001 From: Pell Date: Tue, 29 Apr 2025 09:46:52 +0200 Subject: [PATCH 05/15] Routes to interfaces --- .../random/user/presentation/navigation/BaseNavRoutes.kt | 6 +++--- .../kotlin/com/random/users/users/navigation/UsersRoute.kt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/presentation/src/main/kotlin/com/random/user/presentation/navigation/BaseNavRoutes.kt b/core/presentation/src/main/kotlin/com/random/user/presentation/navigation/BaseNavRoutes.kt index 441ad98..1a0c022 100644 --- a/core/presentation/src/main/kotlin/com/random/user/presentation/navigation/BaseNavRoutes.kt +++ b/core/presentation/src/main/kotlin/com/random/user/presentation/navigation/BaseNavRoutes.kt @@ -2,10 +2,10 @@ package com.random.user.presentation.navigation import kotlinx.serialization.Serializable -sealed class BaseNavRoutes { +sealed interface BaseNavRoutes { @Serializable - data object MainGraph : BaseNavRoutes() + data object MainGraph : BaseNavRoutes @Serializable - data object Users : BaseNavRoutes() + data object Users : BaseNavRoutes } diff --git a/presentation/users/src/main/kotlin/com/random/users/users/navigation/UsersRoute.kt b/presentation/users/src/main/kotlin/com/random/users/users/navigation/UsersRoute.kt index 423899f..2e60d5f 100644 --- a/presentation/users/src/main/kotlin/com/random/users/users/navigation/UsersRoute.kt +++ b/presentation/users/src/main/kotlin/com/random/users/users/navigation/UsersRoute.kt @@ -3,12 +3,12 @@ package com.random.users.users.navigation import com.random.users.users.model.UserUiModel import kotlinx.serialization.Serializable -internal sealed class UsersRoute { +internal sealed interface UsersRoute { @Serializable - data object Home : UsersRoute() + data object Home : UsersRoute @Serializable data class UserDetail( val user: UserUiModel, - ) : UsersRoute() + ) : UsersRoute } From 245aa820e987331fe1873138597469da11d94216 Mon Sep 17 00:00:00 2001 From: Pell Date: Tue, 29 Apr 2025 15:28:23 +0200 Subject: [PATCH 06/15] Unused import --- .../main/kotlin/com/random/user/navigation/RandomUsersNavHost.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/kotlin/com/random/user/navigation/RandomUsersNavHost.kt b/app/src/main/kotlin/com/random/user/navigation/RandomUsersNavHost.kt index a023dea..0f6506e 100644 --- a/app/src/main/kotlin/com/random/user/navigation/RandomUsersNavHost.kt +++ b/app/src/main/kotlin/com/random/user/navigation/RandomUsersNavHost.kt @@ -8,7 +8,6 @@ import androidx.navigation.compose.NavHost import androidx.navigation.navigation import com.random.user.navigation.viewmodel.NavigationViewModel import com.random.user.presentation.navigation.BaseNavRoutes -import com.random.user.presentation.ui.theme.RandomUsersTheme @Composable fun BaseProjectApplicationNavHost( From cd8000f7244c8cb0178bab5cdcef2ecab4bca205 Mon Sep 17 00:00:00 2001 From: Pell Date: Tue, 29 Apr 2025 16:05:42 +0200 Subject: [PATCH 07/15] Room integration tests --- .../UsersViewModelIntegrationTest.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelIntegrationTest.kt b/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelIntegrationTest.kt index cbebb1d..48a2197 100644 --- a/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelIntegrationTest.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelIntegrationTest.kt @@ -92,6 +92,28 @@ internal class UsersViewModelIntegrationTest { } } + @Test + fun `GIVEN getUsersListUseCase returns users WHEN delete user THEN receives users without deleted one`() = + runTest { + initViewModel() + mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody(getUserListResponsePage1Json)) + + viewModel.handleEvent(UsersUiEvent.OnDeleteUser("1")) + runCurrent() + viewModel.handleEvent(UsersUiEvent.OnLoadUsers) + runCurrent() + + viewModel.uiState.test { + val initialState = awaitItem() + val finalState = awaitItem() + assertTrue(initialState.contentState is UsersScreenUiState.ContentState.Loading) + assertTrue(finalState.contentState is UsersScreenUiState.ContentState.Idle) + assertTrue(finalState.users.isNotEmpty()) + assertTrue(finalState.users.find { it.user.uuid == "1" } == null) + expectNoEvents() + } + } + @Test fun `GIVEN getUsersListUseCase returns error WHEN load users event THEN receives Error state`() = runTest { From 32b51f1be1c5653770b104c229c85f1e200036ed Mon Sep 17 00:00:00 2001 From: Pell Date: Tue, 29 Apr 2025 16:40:19 +0200 Subject: [PATCH 08/15] Removed allow main thread room in memory database --- .../kotlin/com/random/users/database/di/TestDatabaseModule.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/core/database/src/main/kotlin/com/random/users/database/di/TestDatabaseModule.kt b/core/database/src/main/kotlin/com/random/users/database/di/TestDatabaseModule.kt index fb761ad..50a47c6 100644 --- a/core/database/src/main/kotlin/com/random/users/database/di/TestDatabaseModule.kt +++ b/core/database/src/main/kotlin/com/random/users/database/di/TestDatabaseModule.kt @@ -23,7 +23,6 @@ object TestDatabaseModule { @ApplicationContext appContext: Context, ) = Room .inMemoryDatabaseBuilder(appContext, RandomUsersDatabase::class.java) - .allowMainThreadQueries() .build() @Provides From 03b0a939cddf72302d33bc1bf6fad89d1ddfe9cc Mon Sep 17 00:00:00 2001 From: Pell Date: Tue, 29 Apr 2025 16:40:35 +0200 Subject: [PATCH 09/15] Fixed rules --- .../users/users/screenshot/UserDetailScreenshotTest.kt | 4 ---- .../users/users/screenshot/UsersScreenshotTest.kt | 10 +++------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UserDetailScreenshotTest.kt b/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UserDetailScreenshotTest.kt index 35ef5f4..fcf7a47 100644 --- a/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UserDetailScreenshotTest.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UserDetailScreenshotTest.kt @@ -1,7 +1,6 @@ package com.random.users.users.screenshot -import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.compose.ui.test.onRoot import androidx.navigation.compose.rememberNavController import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -31,9 +30,6 @@ import kotlin.test.Test sdk = [34], ) internal class UserDetailScreenshotTest { - @get:Rule - val instantRule = InstantTaskExecutorRule() - @get:Rule val composeTestRule = createScreenshotTestComposeRule() diff --git a/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UsersScreenshotTest.kt b/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UsersScreenshotTest.kt index 3047f3b..84465bb 100644 --- a/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UsersScreenshotTest.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UsersScreenshotTest.kt @@ -1,7 +1,6 @@ package com.random.users.users.screenshot -import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.compose.ui.test.click import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onRoot @@ -43,16 +42,13 @@ import kotlin.test.Test sdk = [34], ) internal class UsersScreenshotTest { - @get:Rule(order = 1) - var instantRule: TestRule = InstantTaskExecutorRule() - - @get:Rule(order = 2) + @get:Rule(order = 0) var mainRule: TestRule = MainDispatcherRule() - @get:Rule(order = 3) + @get:Rule(order = 1) val composeTestRule = createScreenshotTestComposeRule() - @get:Rule(order = 4) + @get:Rule(order = 2) val roborazziRule = createRoborazziRule(composeTestRule = composeTestRule, captureType = RoborazziRule.CaptureType.None) From b8aa3efa861b67d0246f302c46574a800cbf6c82 Mon Sep 17 00:00:00 2001 From: Pell Date: Wed, 30 Apr 2025 08:21:03 +0200 Subject: [PATCH 10/15] SnapshotFlow to searchView --- .../random/users/users/composable/UserList.kt | 3 ++- .../users/users/composable/UserSearchView.kt | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/presentation/users/src/main/kotlin/com/random/users/users/composable/UserList.kt b/presentation/users/src/main/kotlin/com/random/users/users/composable/UserList.kt index 47b3f69..270a2cc 100644 --- a/presentation/users/src/main/kotlin/com/random/users/users/composable/UserList.kt +++ b/presentation/users/src/main/kotlin/com/random/users/users/composable/UserList.kt @@ -37,6 +37,7 @@ import com.random.user.presentation.ui.theme.RandomUsersTheme import com.random.users.users.contract.UserUiState import com.random.users.users.contract.UsersScreenUiState import com.random.users.users.model.UserUiModel +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter @@ -61,7 +62,7 @@ internal fun UserList( snapshotFlow { reachedBottom } .distinctUntilChanged() .filter { it && state.contentState is UsersScreenUiState.ContentState.Idle } - .collect { onLoadUsers() } + .collectLatest { onLoadUsers() } } LaunchedEffect( diff --git a/presentation/users/src/main/kotlin/com/random/users/users/composable/UserSearchView.kt b/presentation/users/src/main/kotlin/com/random/users/users/composable/UserSearchView.kt index cf4b930..18b1522 100644 --- a/presentation/users/src/main/kotlin/com/random/users/users/composable/UserSearchView.kt +++ b/presentation/users/src/main/kotlin/com/random/users/users/composable/UserSearchView.kt @@ -9,13 +9,20 @@ import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.tooling.preview.PreviewLightDark import com.random.user.presentation.ui.theme.RandomUsersTheme +import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.distinctUntilChanged +@OptIn(FlowPreview::class) @Composable internal fun UserSearchView( modifier: Modifier = Modifier, @@ -24,6 +31,15 @@ internal fun UserSearchView( ) { val searchState = rememberSaveable { mutableStateOf(search) } + LaunchedEffect( + searchState.value, + ) { + snapshotFlow { searchState.value } + .distinctUntilChanged() + .debounce(200) + .collectLatest { onValueChange(it) } + } + TextField( modifier = modifier.fillMaxWidth().testTag("searchField"), value = searchState.value, From b393ab3c15a9cc73b906597c9b73a7932d2128c8 Mon Sep 17 00:00:00 2001 From: Pell Date: Thu, 1 May 2025 07:26:39 +0200 Subject: [PATCH 11/15] Moved hilt test modules to test folders --- .../com/random/users/api/di/TestApiModule.kt | 56 ------------------- .../com/random/users/api/di/TestApiModule.kt | 2 + .../users/database/di/TestDatabaseModule.kt | 32 ----------- .../users/database/di/TestDatabaseModule.kt | 2 + .../preferences/di/TestPreferencesModule.kt | 31 ---------- .../preferences/di/TestPreferencesModule.kt | 2 + .../users/test/rules/DispatcherRules.kt | 25 --------- .../random/users/test/rules/RoborazziRules.kt | 35 ------------ .../users/data/di/TestDispatchersModule.kt | 20 ------- .../users/data/di/TestDispatchersModule.kt | 2 + 10 files changed, 8 insertions(+), 199 deletions(-) delete mode 100644 core/api/src/main/kotlin/com/random/users/api/di/TestApiModule.kt create mode 100644 core/api/src/test/kotlin/com/random/users/api/di/TestApiModule.kt delete mode 100644 core/database/src/main/kotlin/com/random/users/database/di/TestDatabaseModule.kt create mode 100644 core/database/src/test/kotlin/com/random/users/database/di/TestDatabaseModule.kt delete mode 100644 core/preferences/src/main/kotlin/com/random/users/preferences/di/TestPreferencesModule.kt create mode 100644 core/preferences/src/test/kotlin/com/random/users/preferences/di/TestPreferencesModule.kt delete mode 100644 core/test/src/main/kotlin/com/random/users/test/rules/DispatcherRules.kt delete mode 100644 core/test/src/main/kotlin/com/random/users/test/rules/RoborazziRules.kt delete mode 100644 data/src/main/kotlin/com/random/users/data/di/TestDispatchersModule.kt create mode 100644 data/src/test/kotlin/com/random/users/data/di/TestDispatchersModule.kt diff --git a/core/api/src/main/kotlin/com/random/users/api/di/TestApiModule.kt b/core/api/src/main/kotlin/com/random/users/api/di/TestApiModule.kt deleted file mode 100644 index f2e6ea2..0000000 --- a/core/api/src/main/kotlin/com/random/users/api/di/TestApiModule.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.random.users.api.di - -import arrow.retrofit.adapter.either.EitherCallAdapterFactory -import com.random.users.api.api.UsersApi -import dagger.Module -import dagger.Provides -import dagger.hilt.components.SingletonComponent -import dagger.hilt.testing.TestInstallIn -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor -import okhttp3.mockwebserver.MockWebServer -import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory -import javax.inject.Singleton - -@Module -@TestInstallIn( - components = [SingletonComponent::class], - replaces = [ApiModule::class], -) -object TestApiModule { - @Provides - @Singleton - fun provideOkHttpClient(): OkHttpClient { - val logging = HttpLoggingInterceptor() - logging.setLevel(HttpLoggingInterceptor.Level.BODY) - return OkHttpClient - .Builder() - .addInterceptor(logging) - .build() - } - - @Provides - @Singleton - fun provideUsersApi(retrofit: Retrofit): UsersApi = retrofit.create(UsersApi::class.java) - - @Provides - @Singleton - fun provideRetrofit( - okHttpClient: OkHttpClient, - mockWebServer: MockWebServer, - ): Retrofit { - mockWebServer.start() - return Retrofit - .Builder() - .baseUrl(mockWebServer.url("/")) - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(EitherCallAdapterFactory.create()) - .client(okHttpClient) - .build() - } - - @Provides - @Singleton - fun provideMockWebServer(): MockWebServer = MockWebServer() -} diff --git a/core/api/src/test/kotlin/com/random/users/api/di/TestApiModule.kt b/core/api/src/test/kotlin/com/random/users/api/di/TestApiModule.kt new file mode 100644 index 0000000..2c3dbf6 --- /dev/null +++ b/core/api/src/test/kotlin/com/random/users/api/di/TestApiModule.kt @@ -0,0 +1,2 @@ +package com.random.users.api.di + diff --git a/core/database/src/main/kotlin/com/random/users/database/di/TestDatabaseModule.kt b/core/database/src/main/kotlin/com/random/users/database/di/TestDatabaseModule.kt deleted file mode 100644 index fb761ad..0000000 --- a/core/database/src/main/kotlin/com/random/users/database/di/TestDatabaseModule.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.random.users.database.di - -import android.content.Context -import androidx.room.Room -import com.random.users.database.RandomUsersDatabase -import com.random.users.database.dao.UserDao -import dagger.Module -import dagger.Provides -import dagger.hilt.android.qualifiers.ApplicationContext -import dagger.hilt.components.SingletonComponent -import dagger.hilt.testing.TestInstallIn -import javax.inject.Singleton - -@Module -@TestInstallIn( - components = [SingletonComponent::class], - replaces = [DatabaseModule::class], -) -object TestDatabaseModule { - @Provides - @Singleton - fun provideDatabase( - @ApplicationContext appContext: Context, - ) = Room - .inMemoryDatabaseBuilder(appContext, RandomUsersDatabase::class.java) - .allowMainThreadQueries() - .build() - - @Provides - @Singleton - fun provideUserDao(db: RandomUsersDatabase): UserDao = db.userDao() -} diff --git a/core/database/src/test/kotlin/com/random/users/database/di/TestDatabaseModule.kt b/core/database/src/test/kotlin/com/random/users/database/di/TestDatabaseModule.kt new file mode 100644 index 0000000..5871f03 --- /dev/null +++ b/core/database/src/test/kotlin/com/random/users/database/di/TestDatabaseModule.kt @@ -0,0 +1,2 @@ +package com.random.users.database.di + diff --git a/core/preferences/src/main/kotlin/com/random/users/preferences/di/TestPreferencesModule.kt b/core/preferences/src/main/kotlin/com/random/users/preferences/di/TestPreferencesModule.kt deleted file mode 100644 index 58d4933..0000000 --- a/core/preferences/src/main/kotlin/com/random/users/preferences/di/TestPreferencesModule.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.random.users.preferences.di - -import android.content.Context -import android.content.SharedPreferences -import com.random.users.preferences.manager.PreferencesManager -import dagger.Module -import dagger.Provides -import dagger.hilt.android.qualifiers.ApplicationContext -import dagger.hilt.components.SingletonComponent -import dagger.hilt.testing.TestInstallIn -import javax.inject.Singleton - -@Module -@TestInstallIn( - components = [SingletonComponent::class], - replaces = [PreferencesModule::class], -) -object TestPreferencesModule { - private const val TEST_PREFERENCES_NAME = "test_preferences" - - @Provides - @Singleton - fun provideFakeSharedPreferences( - @ApplicationContext context: Context, - ): SharedPreferences = context.getSharedPreferences(TEST_PREFERENCES_NAME, Context.MODE_PRIVATE) - - @Provides - @Singleton - fun providePreferencesManager(sharedPreferences: SharedPreferences): PreferencesManager = - PreferencesManager(sharedPreferences) -} diff --git a/core/preferences/src/test/kotlin/com/random/users/preferences/di/TestPreferencesModule.kt b/core/preferences/src/test/kotlin/com/random/users/preferences/di/TestPreferencesModule.kt new file mode 100644 index 0000000..aa37c16 --- /dev/null +++ b/core/preferences/src/test/kotlin/com/random/users/preferences/di/TestPreferencesModule.kt @@ -0,0 +1,2 @@ +package com.random.users.preferences.di + diff --git a/core/test/src/main/kotlin/com/random/users/test/rules/DispatcherRules.kt b/core/test/src/main/kotlin/com/random/users/test/rules/DispatcherRules.kt deleted file mode 100644 index a79dd0f..0000000 --- a/core/test/src/main/kotlin/com/random/users/test/rules/DispatcherRules.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.random.users.test.rules - -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.StandardTestDispatcher -import kotlinx.coroutines.test.TestDispatcher -import kotlinx.coroutines.test.resetMain -import kotlinx.coroutines.test.setMain -import org.junit.rules.TestWatcher -import org.junit.runner.Description - -@OptIn(ExperimentalCoroutinesApi::class) -class MainDispatcherRule( - private val testDispatcher: TestDispatcher = StandardTestDispatcher(), -) : TestWatcher() { - override fun starting(description: Description) { - super.starting(description) - Dispatchers.setMain(testDispatcher) - } - - override fun finished(description: Description) { - super.finished(description) - Dispatchers.resetMain() - } -} diff --git a/core/test/src/main/kotlin/com/random/users/test/rules/RoborazziRules.kt b/core/test/src/main/kotlin/com/random/users/test/rules/RoborazziRules.kt deleted file mode 100644 index ea10a90..0000000 --- a/core/test/src/main/kotlin/com/random/users/test/rules/RoborazziRules.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.random.users.test.rules - -import androidx.activity.ComponentActivity -import androidx.compose.ui.test.junit4.AndroidComposeTestRule -import androidx.compose.ui.test.junit4.createAndroidComposeRule -import androidx.compose.ui.test.onRoot -import com.github.takahirom.roborazzi.RoborazziOptions -import com.github.takahirom.roborazzi.RoborazziRule - -fun createRoborazziRule( - composeTestRule: AndroidComposeTestRule<*, *>, - captureType: RoborazziRule.CaptureType = RoborazziRule.CaptureType.LastImage(onlyFail = false), -): RoborazziRule = - RoborazziRule( - composeRule = composeTestRule, - captureRoot = composeTestRule.onRoot(), - options = - RoborazziRule.Options( - outputDirectoryPath = "screenshots", - roborazziOptions = - RoborazziOptions( - recordOptions = - RoborazziOptions.RecordOptions( - resizeScale = 0.5, - ), - compareOptions = - RoborazziOptions.CompareOptions( - changeThreshold = 0.01F, - ), - ), - captureType = captureType, - ), - ) - -fun createScreenshotTestComposeRule() = createAndroidComposeRule() diff --git a/data/src/main/kotlin/com/random/users/data/di/TestDispatchersModule.kt b/data/src/main/kotlin/com/random/users/data/di/TestDispatchersModule.kt deleted file mode 100644 index 93ba312..0000000 --- a/data/src/main/kotlin/com/random/users/data/di/TestDispatchersModule.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.random.users.data.di - -import dagger.Module -import dagger.Provides -import dagger.hilt.components.SingletonComponent -import dagger.hilt.testing.TestInstallIn -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.test.StandardTestDispatcher -import javax.inject.Singleton - -@Module -@TestInstallIn( - components = [SingletonComponent::class], - replaces = [DispatchersModule::class], -) -object TestDispatchersModule { - @Provides - @Singleton - fun provideDispatcher(): CoroutineDispatcher = StandardTestDispatcher() -} diff --git a/data/src/test/kotlin/com/random/users/data/di/TestDispatchersModule.kt b/data/src/test/kotlin/com/random/users/data/di/TestDispatchersModule.kt new file mode 100644 index 0000000..a28b68b --- /dev/null +++ b/data/src/test/kotlin/com/random/users/data/di/TestDispatchersModule.kt @@ -0,0 +1,2 @@ +package com.random.users.data.di + From 705a7d25f9ba397600357b4585aeab27e83e43f8 Mon Sep 17 00:00:00 2001 From: Pell Date: Thu, 1 May 2025 08:16:26 +0200 Subject: [PATCH 12/15] Added test modules --- .../com/random/users/api/di/TestApiModule.kt | 44 +++++++++++++++++++ .../users/database/di/TestDatabaseModule.kt | 30 +++++++++++++ .../preferences/di/TestPreferencesModule.kt | 29 ++++++++++++ .../users/data/di/TestDispatchersModule.kt | 18 ++++++++ .../repository/UsersRepositoryUnitTest.kt | 2 +- .../usecase/GetUserListUseCaseUnitTest.kt | 2 +- 6 files changed, 123 insertions(+), 2 deletions(-) diff --git a/core/api/src/test/kotlin/com/random/users/api/di/TestApiModule.kt b/core/api/src/test/kotlin/com/random/users/api/di/TestApiModule.kt index 2c3dbf6..c9a0c81 100644 --- a/core/api/src/test/kotlin/com/random/users/api/di/TestApiModule.kt +++ b/core/api/src/test/kotlin/com/random/users/api/di/TestApiModule.kt @@ -1,2 +1,46 @@ package com.random.users.api.di +import arrow.retrofit.adapter.either.EitherCallAdapterFactory +import com.random.users.api.api.UsersApi +import dagger.Module +import dagger.Provides +import dagger.hilt.components.SingletonComponent +import dagger.hilt.testing.TestInstallIn +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import javax.inject.Singleton + +@Module +@TestInstallIn( + components = [SingletonComponent::class], + replaces = [ApiModule::class], +) +object TestApiModule { + @Provides + @Singleton + fun provideOkHttpClient(): OkHttpClient { + val logging = HttpLoggingInterceptor() + logging.setLevel(HttpLoggingInterceptor.Level.BODY) + return OkHttpClient + .Builder() + .addInterceptor(logging) + .build() + } + + @Provides + @Singleton + fun provideUsersApi(retrofit: Retrofit): UsersApi = retrofit.create(UsersApi::class.java) + + @Provides + @Singleton + fun provideRetrofit(okHttpClient: OkHttpClient) = + Retrofit + .Builder() + .baseUrl("http://localhost:8080/") + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(EitherCallAdapterFactory.create()) + .client(okHttpClient) + .build() +} diff --git a/core/database/src/test/kotlin/com/random/users/database/di/TestDatabaseModule.kt b/core/database/src/test/kotlin/com/random/users/database/di/TestDatabaseModule.kt index 5871f03..fb761ad 100644 --- a/core/database/src/test/kotlin/com/random/users/database/di/TestDatabaseModule.kt +++ b/core/database/src/test/kotlin/com/random/users/database/di/TestDatabaseModule.kt @@ -1,2 +1,32 @@ package com.random.users.database.di +import android.content.Context +import androidx.room.Room +import com.random.users.database.RandomUsersDatabase +import com.random.users.database.dao.UserDao +import dagger.Module +import dagger.Provides +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import dagger.hilt.testing.TestInstallIn +import javax.inject.Singleton + +@Module +@TestInstallIn( + components = [SingletonComponent::class], + replaces = [DatabaseModule::class], +) +object TestDatabaseModule { + @Provides + @Singleton + fun provideDatabase( + @ApplicationContext appContext: Context, + ) = Room + .inMemoryDatabaseBuilder(appContext, RandomUsersDatabase::class.java) + .allowMainThreadQueries() + .build() + + @Provides + @Singleton + fun provideUserDao(db: RandomUsersDatabase): UserDao = db.userDao() +} diff --git a/core/preferences/src/test/kotlin/com/random/users/preferences/di/TestPreferencesModule.kt b/core/preferences/src/test/kotlin/com/random/users/preferences/di/TestPreferencesModule.kt index aa37c16..58d4933 100644 --- a/core/preferences/src/test/kotlin/com/random/users/preferences/di/TestPreferencesModule.kt +++ b/core/preferences/src/test/kotlin/com/random/users/preferences/di/TestPreferencesModule.kt @@ -1,2 +1,31 @@ package com.random.users.preferences.di +import android.content.Context +import android.content.SharedPreferences +import com.random.users.preferences.manager.PreferencesManager +import dagger.Module +import dagger.Provides +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import dagger.hilt.testing.TestInstallIn +import javax.inject.Singleton + +@Module +@TestInstallIn( + components = [SingletonComponent::class], + replaces = [PreferencesModule::class], +) +object TestPreferencesModule { + private const val TEST_PREFERENCES_NAME = "test_preferences" + + @Provides + @Singleton + fun provideFakeSharedPreferences( + @ApplicationContext context: Context, + ): SharedPreferences = context.getSharedPreferences(TEST_PREFERENCES_NAME, Context.MODE_PRIVATE) + + @Provides + @Singleton + fun providePreferencesManager(sharedPreferences: SharedPreferences): PreferencesManager = + PreferencesManager(sharedPreferences) +} diff --git a/data/src/test/kotlin/com/random/users/data/di/TestDispatchersModule.kt b/data/src/test/kotlin/com/random/users/data/di/TestDispatchersModule.kt index a28b68b..93ba312 100644 --- a/data/src/test/kotlin/com/random/users/data/di/TestDispatchersModule.kt +++ b/data/src/test/kotlin/com/random/users/data/di/TestDispatchersModule.kt @@ -1,2 +1,20 @@ package com.random.users.data.di +import dagger.Module +import dagger.Provides +import dagger.hilt.components.SingletonComponent +import dagger.hilt.testing.TestInstallIn +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.test.StandardTestDispatcher +import javax.inject.Singleton + +@Module +@TestInstallIn( + components = [SingletonComponent::class], + replaces = [DispatchersModule::class], +) +object TestDispatchersModule { + @Provides + @Singleton + fun provideDispatcher(): CoroutineDispatcher = StandardTestDispatcher() +} diff --git a/data/src/test/kotlin/com/random/users/data/repository/UsersRepositoryUnitTest.kt b/data/src/test/kotlin/com/random/users/data/repository/UsersRepositoryUnitTest.kt index 2101987..a3c8f22 100644 --- a/data/src/test/kotlin/com/random/users/data/repository/UsersRepositoryUnitTest.kt +++ b/data/src/test/kotlin/com/random/users/data/repository/UsersRepositoryUnitTest.kt @@ -19,7 +19,7 @@ import org.junit.Assert import org.junit.Before import org.junit.Test -class UsersRepositoryUnitTest { +internal class UsersRepositoryUnitTest { private lateinit var usersRepository: UsersRepository private val usersLocalDataSource: UsersLocalDataSource = mockk() private val usersRemoteDataSource: UsersRemoteDataSource = mockk() diff --git a/domain/src/test/kotlin/com/random/users/domain/usecase/GetUserListUseCaseUnitTest.kt b/domain/src/test/kotlin/com/random/users/domain/usecase/GetUserListUseCaseUnitTest.kt index 32a1d6a..dab0780 100644 --- a/domain/src/test/kotlin/com/random/users/domain/usecase/GetUserListUseCaseUnitTest.kt +++ b/domain/src/test/kotlin/com/random/users/domain/usecase/GetUserListUseCaseUnitTest.kt @@ -14,7 +14,7 @@ import org.junit.Assert import org.junit.Before import org.junit.Test -class GetUserListUseCaseUnitTest { +internal class GetUserListUseCaseUnitTest { private lateinit var usersRepository: UsersRepository private lateinit var getUserListUseCase: GetUserListUseCase From b4f181dbf73aeb8c79b7f3f0394b472bbaa947bc Mon Sep 17 00:00:00 2001 From: Pell Date: Fri, 2 May 2025 08:48:19 +0200 Subject: [PATCH 13/15] Test fixtures --- core/api/build.gradle.kts | 13 +++++- .../com/random/users/api/di/TestApiModule.kt | 0 core/test/.gitignore | 1 - core/test/build.gradle.kts | 46 ------------------- core/test/proguard-rules.pro | 21 --------- gradle.properties | 1 + presentation/users/build.gradle.kts | 2 +- .../users}/model/getUsersListResponseJson.kt | 0 .../users/users/rules/DispatcherRules.kt | 4 ++ .../users/users/rules/RoborrazziRules.kt | 4 ++ 10 files changed, 21 insertions(+), 71 deletions(-) rename core/api/src/{test => testFixtures}/kotlin/com/random/users/api/di/TestApiModule.kt (100%) delete mode 100644 core/test/.gitignore delete mode 100644 core/test/build.gradle.kts delete mode 100644 core/test/proguard-rules.pro rename {core/test/src/main/kotlin/com/random/users/test => presentation/users/src/test/kotlin/com/random/users/users}/model/getUsersListResponseJson.kt (100%) create mode 100644 presentation/users/src/test/kotlin/com/random/users/users/rules/DispatcherRules.kt create mode 100644 presentation/users/src/test/kotlin/com/random/users/users/rules/RoborrazziRules.kt diff --git a/core/api/build.gradle.kts b/core/api/build.gradle.kts index 99b1d20..24d6c3f 100644 --- a/core/api/build.gradle.kts +++ b/core/api/build.gradle.kts @@ -30,6 +30,9 @@ android { kotlinOptions { jvmTarget = AppVersions.JVM_TARGET } + testFixtures { + enable = true + } } dependencies { @@ -39,8 +42,14 @@ dependencies { implementation(libs.retrofit.gson) implementation(libs.okhttp) implementation(libs.okhttp.logging.interceptor) - implementation(libs.hilt.testing) - implementation(libs.mockwebserver) ksp(libs.com.google.dagger.hilt.compiler) + + kspTestFixtures(libs.com.google.dagger.hilt.compiler) + testFixturesImplementation(libs.hilt.testing) + testFixturesImplementation(libs.arrow.core.retrofit) + testFixturesImplementation(libs.retrofit) + testFixturesImplementation(libs.retrofit.gson) + testFixturesImplementation(libs.okhttp) + testFixturesImplementation(libs.okhttp.logging.interceptor) } diff --git a/core/api/src/test/kotlin/com/random/users/api/di/TestApiModule.kt b/core/api/src/testFixtures/kotlin/com/random/users/api/di/TestApiModule.kt similarity index 100% rename from core/api/src/test/kotlin/com/random/users/api/di/TestApiModule.kt rename to core/api/src/testFixtures/kotlin/com/random/users/api/di/TestApiModule.kt diff --git a/core/test/.gitignore b/core/test/.gitignore deleted file mode 100644 index 42afabf..0000000 --- a/core/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/core/test/build.gradle.kts b/core/test/build.gradle.kts deleted file mode 100644 index c187512..0000000 --- a/core/test/build.gradle.kts +++ /dev/null @@ -1,46 +0,0 @@ -plugins { - alias(libs.plugins.android.library) - alias(libs.plugins.kotlin.android) - alias(libs.plugins.com.google.devtools.ksp) - alias(libs.plugins.com.google.dagger.hilt.android) -} - -android { - namespace = "${AppVersions.APPLICATION_ID}.core.test" - compileSdk = AppVersions.COMPILE_SDK - - defaultConfig { - minSdk = AppVersions.MIN_SDK - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - isMinifyEnabled = false - proguardFiles( - getDefaultProguardFile("proguard-android-optimize.txt"), - "proguard-rules.pro", - ) - } - } - compileOptions { - sourceCompatibility = AppVersions.javaVersion - targetCompatibility = AppVersions.javaVersion - } - kotlinOptions { - jvmTarget = AppVersions.JVM_TARGET - } - testOptions { - unitTests { - isIncludeAndroidResources = true - } - } -} - -dependencies { - implementation(libs.bundles.layer.data) - ksp(libs.com.google.dagger.hilt.compiler) - implementation(libs.bundles.test.compose) - - testImplementation(libs.bundles.test.unit) -} diff --git a/core/test/proguard-rules.pro b/core/test/proguard-rules.pro deleted file mode 100644 index 481bb43..0000000 --- a/core/test/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index f9ce38f..8300a4a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,3 +22,4 @@ kotlin.code.style=official # thereby reducing the size of the R class for that library android.nonTransitiveRClass=true roborazzi.test.verify=true +android.experimental.enableTestFixturesKotlinSupport=true diff --git a/presentation/users/build.gradle.kts b/presentation/users/build.gradle.kts index c686ab0..d5078e1 100644 --- a/presentation/users/build.gradle.kts +++ b/presentation/users/build.gradle.kts @@ -61,8 +61,8 @@ dependencies { implementation(project(":core:presentation")) implementation(project(":domain")) - testImplementation(project(":core:test")) testImplementation(project(":data")) + testImplementation(testFixtures(project(":core:api"))) testImplementation(libs.bundles.test.unit) testImplementation(libs.bundles.test.compose) } diff --git a/core/test/src/main/kotlin/com/random/users/test/model/getUsersListResponseJson.kt b/presentation/users/src/test/kotlin/com/random/users/users/model/getUsersListResponseJson.kt similarity index 100% rename from core/test/src/main/kotlin/com/random/users/test/model/getUsersListResponseJson.kt rename to presentation/users/src/test/kotlin/com/random/users/users/model/getUsersListResponseJson.kt diff --git a/presentation/users/src/test/kotlin/com/random/users/users/rules/DispatcherRules.kt b/presentation/users/src/test/kotlin/com/random/users/users/rules/DispatcherRules.kt new file mode 100644 index 0000000..3a3bff2 --- /dev/null +++ b/presentation/users/src/test/kotlin/com/random/users/users/rules/DispatcherRules.kt @@ -0,0 +1,4 @@ +package com.random.users.users.rules + +class DispatcherRules { +} diff --git a/presentation/users/src/test/kotlin/com/random/users/users/rules/RoborrazziRules.kt b/presentation/users/src/test/kotlin/com/random/users/users/rules/RoborrazziRules.kt new file mode 100644 index 0000000..bb5542c --- /dev/null +++ b/presentation/users/src/test/kotlin/com/random/users/users/rules/RoborrazziRules.kt @@ -0,0 +1,4 @@ +package com.random.users.users.rules + +class RoborrazziRules { +} From bcd9bfa1c422bd5a28646a3efedb75890ee2e796 Mon Sep 17 00:00:00 2001 From: Pell Date: Fri, 2 May 2025 08:49:31 +0200 Subject: [PATCH 14/15] Core test module deleted and moved to users --- .../users/model/getUsersListResponseJson.kt | 2 +- .../users/users/rules/DispatcherRules.kt | 23 +++++++++++- .../users/users/rules/RoborrazziRules.kt | 35 +++++++++++++++++-- .../screenshot/UserDetailScreenshotTest.kt | 6 ++-- .../users/screenshot/UsersScreenshotTest.kt | 6 ++-- .../UsersViewModelIntegrationTest.kt | 8 ++--- .../users/viewmodel/UsersViewModelUnitTest.kt | 2 +- settings.gradle.kts | 1 - 8 files changed, 67 insertions(+), 16 deletions(-) diff --git a/presentation/users/src/test/kotlin/com/random/users/users/model/getUsersListResponseJson.kt b/presentation/users/src/test/kotlin/com/random/users/users/model/getUsersListResponseJson.kt index 61a2dbc..c2956c1 100644 --- a/presentation/users/src/test/kotlin/com/random/users/users/model/getUsersListResponseJson.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/model/getUsersListResponseJson.kt @@ -1,4 +1,4 @@ -package com.random.users.test.model +package com.random.users.users.model val getUserListResponsePage1Json = """ diff --git a/presentation/users/src/test/kotlin/com/random/users/users/rules/DispatcherRules.kt b/presentation/users/src/test/kotlin/com/random/users/users/rules/DispatcherRules.kt index 3a3bff2..dc13154 100644 --- a/presentation/users/src/test/kotlin/com/random/users/users/rules/DispatcherRules.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/rules/DispatcherRules.kt @@ -1,4 +1,25 @@ package com.random.users.users.rules -class DispatcherRules { +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestDispatcher +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.setMain +import org.junit.rules.TestWatcher +import org.junit.runner.Description + +@OptIn(ExperimentalCoroutinesApi::class) +class MainDispatcherRule( + private val testDispatcher: TestDispatcher = StandardTestDispatcher(), +) : TestWatcher() { + override fun starting(description: Description) { + super.starting(description) + Dispatchers.setMain(testDispatcher) + } + + override fun finished(description: Description) { + super.finished(description) + Dispatchers.resetMain() + } } diff --git a/presentation/users/src/test/kotlin/com/random/users/users/rules/RoborrazziRules.kt b/presentation/users/src/test/kotlin/com/random/users/users/rules/RoborrazziRules.kt index bb5542c..c534076 100644 --- a/presentation/users/src/test/kotlin/com/random/users/users/rules/RoborrazziRules.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/rules/RoborrazziRules.kt @@ -1,4 +1,35 @@ package com.random.users.users.rules -class RoborrazziRules { -} +import androidx.activity.ComponentActivity +import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onRoot +import com.github.takahirom.roborazzi.RoborazziOptions +import com.github.takahirom.roborazzi.RoborazziRule + +fun createRoborazziRule( + composeTestRule: AndroidComposeTestRule<*, *>, + captureType: RoborazziRule.CaptureType = RoborazziRule.CaptureType.LastImage(onlyFail = false), +): RoborazziRule = + RoborazziRule( + composeRule = composeTestRule, + captureRoot = composeTestRule.onRoot(), + options = + RoborazziRule.Options( + outputDirectoryPath = "screenshots", + roborazziOptions = + RoborazziOptions( + recordOptions = + RoborazziOptions.RecordOptions( + resizeScale = 0.5, + ), + compareOptions = + RoborazziOptions.CompareOptions( + changeThreshold = 0.01F, + ), + ), + captureType = captureType, + ), + ) + +fun createScreenshotTestComposeRule() = createAndroidComposeRule() diff --git a/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UserDetailScreenshotTest.kt b/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UserDetailScreenshotTest.kt index fcf7a47..8c101b1 100644 --- a/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UserDetailScreenshotTest.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UserDetailScreenshotTest.kt @@ -7,9 +7,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.github.takahirom.roborazzi.RobolectricDeviceQualifiers import com.github.takahirom.roborazzi.RoborazziRule import com.github.takahirom.roborazzi.captureRoboImage -import com.random.users.test.rules.MainDispatcherRule -import com.random.users.test.rules.createRoborazziRule -import com.random.users.test.rules.createScreenshotTestComposeRule +import com.random.users.users.rules.MainDispatcherRule +import com.random.users.users.rules.createRoborazziRule +import com.random.users.users.rules.createScreenshotTestComposeRule import com.random.users.users.mapper.toUiModel import com.random.users.users.mother.UserMother import com.random.users.users.screen.UserDetailScreen diff --git a/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UsersScreenshotTest.kt b/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UsersScreenshotTest.kt index 84465bb..9230744 100644 --- a/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UsersScreenshotTest.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/screenshot/UsersScreenshotTest.kt @@ -15,9 +15,9 @@ import com.github.takahirom.roborazzi.captureRoboImage import com.random.users.domain.models.UsersErrors import com.random.users.domain.usecase.DeleteUserUseCase import com.random.users.domain.usecase.GetUserListUseCase -import com.random.users.test.rules.MainDispatcherRule -import com.random.users.test.rules.createRoborazziRule -import com.random.users.test.rules.createScreenshotTestComposeRule +import com.random.users.users.rules.MainDispatcherRule +import com.random.users.users.rules.createRoborazziRule +import com.random.users.users.rules.createScreenshotTestComposeRule import com.random.users.users.mother.UserMother import com.random.users.users.screen.UsersScreen import com.random.users.users.viewmodel.UsersViewModel diff --git a/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelIntegrationTest.kt b/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelIntegrationTest.kt index 48a2197..2e345cd 100644 --- a/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelIntegrationTest.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelIntegrationTest.kt @@ -4,8 +4,8 @@ import androidx.arch.core.executor.testing.InstantTaskExecutorRule import app.cash.turbine.test import com.random.users.domain.usecase.DeleteUserUseCase import com.random.users.domain.usecase.GetUserListUseCase -import com.random.users.test.model.getUserListResponsePage1Json -import com.random.users.test.rules.MainDispatcherRule +import com.random.users.users.model.getUserListResponsePage1Json +import com.random.users.users.rules.MainDispatcherRule import com.random.users.users.contract.UsersErrorUiState import com.random.users.users.contract.UsersUiEvent import com.random.users.users.contract.UsersScreenUiState @@ -50,13 +50,13 @@ internal class UsersViewModelIntegrationTest { @Inject lateinit var deleteUserUseCase: DeleteUserUseCase - @Inject lateinit var mockWebServer: MockWebServer - lateinit var viewModel: UsersViewModel @Before fun setup() { + mockWebServer = MockWebServer() + mockWebServer.start(8080) hiltRule.inject() } diff --git a/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelUnitTest.kt b/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelUnitTest.kt index bc8a68a..77faf47 100644 --- a/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelUnitTest.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/viewmodel/UsersViewModelUnitTest.kt @@ -5,7 +5,7 @@ import arrow.core.left import com.random.users.domain.models.UsersErrors import com.random.users.domain.usecase.DeleteUserUseCase import com.random.users.domain.usecase.GetUserListUseCase -import com.random.users.test.rules.MainDispatcherRule +import com.random.users.users.rules.MainDispatcherRule import com.random.users.users.contract.UsersErrorUiState import com.random.users.users.contract.UsersUiEvent import com.random.users.users.contract.UsersScreenUiState diff --git a/settings.gradle.kts b/settings.gradle.kts index 21dbe74..d2edd20 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -25,7 +25,6 @@ include(":core:api") include(":core:database") include(":core:preferences") include(":core:presentation") -include(":core:test") include(":data") include(":domain") include(":presentation:users") From 85c4655700a086f10cdc35ce83fddb2d9198ca48 Mon Sep 17 00:00:00 2001 From: Pell Date: Fri, 2 May 2025 09:17:28 +0200 Subject: [PATCH 15/15] Removed fixtures and moved test di modules to ui feature --- core/api/build.gradle.kts | 11 ----------- core/database/build.gradle.kts | 2 -- core/preferences/build.gradle.kts | 1 - data/build.gradle.kts | 3 --- gradle.properties | 1 - presentation/users/build.gradle.kts | 11 ++++++++++- .../com/random/users/users}/di/TestApiModule.kt | 3 ++- .../com/random/users/users}/di/TestDatabaseModule.kt | 3 ++- .../random/users/users}/di/TestDispatchersModule.kt | 3 ++- .../random/users/users}/di/TestPreferencesModule.kt | 3 ++- 10 files changed, 18 insertions(+), 23 deletions(-) rename {core/api/src/testFixtures/kotlin/com/random/users/api => presentation/users/src/test/kotlin/com/random/users/users}/di/TestApiModule.kt (94%) rename {core/database/src/test/kotlin/com/random/users/database => presentation/users/src/test/kotlin/com/random/users/users}/di/TestDatabaseModule.kt (90%) rename {data/src/test/kotlin/com/random/users/data => presentation/users/src/test/kotlin/com/random/users/users}/di/TestDispatchersModule.kt (86%) rename {core/preferences/src/test/kotlin/com/random/users/preferences => presentation/users/src/test/kotlin/com/random/users/users}/di/TestPreferencesModule.kt (91%) diff --git a/core/api/build.gradle.kts b/core/api/build.gradle.kts index 24d6c3f..fedf2ea 100644 --- a/core/api/build.gradle.kts +++ b/core/api/build.gradle.kts @@ -30,9 +30,6 @@ android { kotlinOptions { jvmTarget = AppVersions.JVM_TARGET } - testFixtures { - enable = true - } } dependencies { @@ -44,12 +41,4 @@ dependencies { implementation(libs.okhttp.logging.interceptor) ksp(libs.com.google.dagger.hilt.compiler) - - kspTestFixtures(libs.com.google.dagger.hilt.compiler) - testFixturesImplementation(libs.hilt.testing) - testFixturesImplementation(libs.arrow.core.retrofit) - testFixturesImplementation(libs.retrofit) - testFixturesImplementation(libs.retrofit.gson) - testFixturesImplementation(libs.okhttp) - testFixturesImplementation(libs.okhttp.logging.interceptor) } diff --git a/core/database/build.gradle.kts b/core/database/build.gradle.kts index 357174b..2681254 100644 --- a/core/database/build.gradle.kts +++ b/core/database/build.gradle.kts @@ -35,8 +35,6 @@ android { dependencies { implementation(libs.bundles.layer.data) implementation(libs.room.ktx) - implementation(libs.room.testing) - implementation(libs.hilt.testing) ksp(libs.com.google.dagger.hilt.compiler) ksp(libs.room.compiler) diff --git a/core/preferences/build.gradle.kts b/core/preferences/build.gradle.kts index f643b90..8d89178 100644 --- a/core/preferences/build.gradle.kts +++ b/core/preferences/build.gradle.kts @@ -34,7 +34,6 @@ android { dependencies { implementation(libs.bundles.layer.data) - implementation(libs.hilt.testing) ksp(libs.com.google.dagger.hilt.compiler) } diff --git a/data/build.gradle.kts b/data/build.gradle.kts index 65b0081..3362d4d 100644 --- a/data/build.gradle.kts +++ b/data/build.gradle.kts @@ -36,9 +36,6 @@ dependencies { implementation(libs.bundles.layer.data) implementation(libs.arrow.core.retrofit) - implementation(libs.hilt.testing) - implementation(libs.test.corutines) - ksp(libs.com.google.dagger.hilt.compiler) implementation(project(":domain")) diff --git a/gradle.properties b/gradle.properties index 8300a4a..f9ce38f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,4 +22,3 @@ kotlin.code.style=official # thereby reducing the size of the R class for that library android.nonTransitiveRClass=true roborazzi.test.verify=true -android.experimental.enableTestFixturesKotlinSupport=true diff --git a/presentation/users/build.gradle.kts b/presentation/users/build.gradle.kts index d5078e1..aff3ebb 100644 --- a/presentation/users/build.gradle.kts +++ b/presentation/users/build.gradle.kts @@ -61,8 +61,17 @@ dependencies { implementation(project(":core:presentation")) implementation(project(":domain")) + kspTest(libs.com.google.dagger.hilt.compiler) testImplementation(project(":data")) - testImplementation(testFixtures(project(":core:api"))) + testImplementation(project(":core:preferences")) + testImplementation(project(":core:database")) + testImplementation(project(":core:api")) + testImplementation(libs.arrow.core.retrofit) + testImplementation(libs.retrofit) + testImplementation(libs.retrofit.gson) + testImplementation(libs.okhttp) + testImplementation(libs.okhttp.logging.interceptor) + testImplementation(libs.room.testing) testImplementation(libs.bundles.test.unit) testImplementation(libs.bundles.test.compose) } diff --git a/core/api/src/testFixtures/kotlin/com/random/users/api/di/TestApiModule.kt b/presentation/users/src/test/kotlin/com/random/users/users/di/TestApiModule.kt similarity index 94% rename from core/api/src/testFixtures/kotlin/com/random/users/api/di/TestApiModule.kt rename to presentation/users/src/test/kotlin/com/random/users/users/di/TestApiModule.kt index c9a0c81..00e6f93 100644 --- a/core/api/src/testFixtures/kotlin/com/random/users/api/di/TestApiModule.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/di/TestApiModule.kt @@ -1,7 +1,8 @@ -package com.random.users.api.di +package com.random.users.users.di import arrow.retrofit.adapter.either.EitherCallAdapterFactory import com.random.users.api.api.UsersApi +import com.random.users.api.di.ApiModule import dagger.Module import dagger.Provides import dagger.hilt.components.SingletonComponent diff --git a/core/database/src/test/kotlin/com/random/users/database/di/TestDatabaseModule.kt b/presentation/users/src/test/kotlin/com/random/users/users/di/TestDatabaseModule.kt similarity index 90% rename from core/database/src/test/kotlin/com/random/users/database/di/TestDatabaseModule.kt rename to presentation/users/src/test/kotlin/com/random/users/users/di/TestDatabaseModule.kt index 50a47c6..1468205 100644 --- a/core/database/src/test/kotlin/com/random/users/database/di/TestDatabaseModule.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/di/TestDatabaseModule.kt @@ -1,9 +1,10 @@ -package com.random.users.database.di +package com.random.users.users.di import android.content.Context import androidx.room.Room import com.random.users.database.RandomUsersDatabase import com.random.users.database.dao.UserDao +import com.random.users.database.di.DatabaseModule import dagger.Module import dagger.Provides import dagger.hilt.android.qualifiers.ApplicationContext diff --git a/data/src/test/kotlin/com/random/users/data/di/TestDispatchersModule.kt b/presentation/users/src/test/kotlin/com/random/users/users/di/TestDispatchersModule.kt similarity index 86% rename from data/src/test/kotlin/com/random/users/data/di/TestDispatchersModule.kt rename to presentation/users/src/test/kotlin/com/random/users/users/di/TestDispatchersModule.kt index 93ba312..c852705 100644 --- a/data/src/test/kotlin/com/random/users/data/di/TestDispatchersModule.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/di/TestDispatchersModule.kt @@ -1,5 +1,6 @@ -package com.random.users.data.di +package com.random.users.users.di +import com.random.users.data.di.DispatchersModule import dagger.Module import dagger.Provides import dagger.hilt.components.SingletonComponent diff --git a/core/preferences/src/test/kotlin/com/random/users/preferences/di/TestPreferencesModule.kt b/presentation/users/src/test/kotlin/com/random/users/users/di/TestPreferencesModule.kt similarity index 91% rename from core/preferences/src/test/kotlin/com/random/users/preferences/di/TestPreferencesModule.kt rename to presentation/users/src/test/kotlin/com/random/users/users/di/TestPreferencesModule.kt index 58d4933..4283352 100644 --- a/core/preferences/src/test/kotlin/com/random/users/preferences/di/TestPreferencesModule.kt +++ b/presentation/users/src/test/kotlin/com/random/users/users/di/TestPreferencesModule.kt @@ -1,7 +1,8 @@ -package com.random.users.preferences.di +package com.random.users.users.di import android.content.Context import android.content.SharedPreferences +import com.random.users.preferences.di.PreferencesModule import com.random.users.preferences.manager.PreferencesManager import dagger.Module import dagger.Provides