I'm currently building a jetpack compose app with Kotlin and I experience difficulties with testing the navigation of the app.
I want to mock my ViewModels so my tests are not dependend of the api and so on. I have tried different things for mocking the viewmodels but none of them worked. I have found out that the way to go is by mocking the factory, but I can't figure out how to do it.
For the initialization of the vm's I have the following factory:
object AppViewModelProvider {
val Factory = viewModelFactory {
initializer {
FavoriteViewModel(fieldFavoritesApplication().container.favoriteRepository)
}
//More initializers...
}
}
fun CreationExtras.fieldFavoritesApplication(): FieldFavoritesApplication =
(this[AndroidViewModelFactory.APPLICATION_KEY] as FieldFavoritesApplication)
Here is the function signature of the navigation host:
fun FieldFavoritesNavHost(
navController: NavHostController,
modifier: Modifier = Modifier,
favoriteViewModel: FavoriteViewModel = viewModel(factory = AppViewModelProvider.Factory)
)
And finally the test itself:
class NavigationTest {
@get:Rule
val composeTestRule = createComposeRule()
lateinit var navController:TestNavHostController
@Before
fun setupAppNavHost() {
composeTestRule.setContent {
navController = TestNavHostController(LocalContext.current)
navController.navigatorProvider.addNavigator(ComposeNavigator())
FieldFavoritesApp(navController)
}
}
@Test
fun verifyStartDestination() {
Assert.assertEquals(LeaguesDestination.route, navController.currentBackStackEntry?.destination?.route)
}
}
How can I mock the factory so I can use fake viewmodels in this test?
To mock a ViewModel
in a project structured similarly to Inventory app you can create ViewModel
file with the same file name and location in the androidTest
source set. For example, if you have FavoriteViewModel
in ui.favorites
package in your app, create ui.favorites
package in androidTest
and put mock FavoriteViewModel
implementation there, it will be used instead of the original one.
Alternatively, you can keep the original ViewModel
s but mock repositories instead in a similar way. For example, if you want to mock ItemsRepository
in Inventory app, create TestItemsRepository
implementing ItemsRepository
in the androidTest
. Then create AppContainer
in data
package that will provide your test implementation:
override val itemsRepository: ItemsRepository by lazy {
TestItemsRepository()
}