How to test ViewModel using AndroidX and Hilt

125 Views Asked by At

I am trying to test my ViewModel class. I believe that I need to use a HiltViewModelTest annotation but, Android Studio cannot find the file..

import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.elnimijogames.porschegarage.MainActivity
import com.elnimijogames.porschegarage.model.MenuItemRepository
import com.elnimijogames.porschegarage.model.MenuPhotoGalleryRepository
import dagger.hilt.android.testing.BindValue
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
import org.junit.runner.RunWith
import javax.inject.Inject

@HiltAndroidTest
@RunWith(AndroidJUnit4::class)
class MainMenuViewModelTest {

    @get:Rule
    var hiltRule = HiltAndroidRule(this)

    @get:Rule
    var activityScenarioRule = ActivityScenarioRule(MainActivity::class.java)

    @Inject
    lateinit var galleryRepository: MenuPhotoGalleryRepository

    @Inject
    lateinit var menuItemRepository: MenuItemRepository

    @BindValue
    @JvmField
    val galleryRepositoryBindValue: MenuPhotoGalleryRepository = galleryRepository

    @BindValue
    @JvmField
    val menuItemRepositoryBindValue: MenuItemRepository = menuItemRepository

    @Before
    fun setup() {
        hiltRule.inject()
    }

    @HiltViewModelTest
    fun testMainMenuViewModel() {
        val viewModel = MainMenuViewModel(galleryRepository, menuItemRepository)

        val expectedGalleryList = galleryRepository.getImageGalleryList()
        val expectedMenuList = menuItemRepository.getMenuItemsList()

        assertEquals(expectedGalleryList, viewModel.photoGalleryState.value)
        assertEquals(expectedMenuList, viewModel.itemMenuState.value)
    }
}

If I remove the annotation I instead get the following error when running the test: MenuPhotoGallery is bound multiple times MenuItemRepository is bound multiple times

I can't see any specific dependency that I should be using that I'm not already using.

Below is the code for my ViewModel:

import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import com.elnimijogames.porschegarage.model.MenuItem
import com.elnimijogames.porschegarage.model.MenuItemRepository
import com.elnimijogames.porschegarage.model.MenuPhotoGalleryRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

@HiltViewModel
class MainMenuViewModel @Inject constructor(
    galleryRepository: MenuPhotoGalleryRepository,
    menuItemRepository: MenuItemRepository
) : ViewModel() {
    val photoGalleryState: MutableState<List<String>> = mutableStateOf(emptyList())
    val itemMenuState: MutableState<List<MenuItem>> = mutableStateOf(emptyList())

    init {
        photoGalleryState.value = galleryRepository.getImageGalleryList()
        itemMenuState.value = menuItemRepository.getMenuItemsList()
    }
}

My module class looks like this:

@Module
@InstallIn(ViewModelComponent::class)
class AppModule {
    @Provides
    fun providesMenuPhotoGalleryRepository(): MenuPhotoGalleryRepository = MenuPhotoGalleryRepository()

    @Provides
    fun providesMenuItemListInterface(): MenuItemListInterface = MenuItemListLocal()

    @Provides
    fun providesMenuItemListLocal(): MenuItemListLocal = MenuItemListLocal()

    @Provides
    fun providesMenuItemRepository(menuItemListLocal: MenuItemListLocal): MenuItemRepository = MenuItemRepository(menuItemListLocal)
}

The MenuPhotoGalleryRepository and MenuItemrepository files are basic classes with no Hilt annotations.

These are the dependencies in my build.gradle file.

implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.activity:activity-compose:1.7.2'
implementation platform('org.jetbrains.kotlin:kotlin-bom:1.8.0')
implementation platform('androidx.compose:compose-bom:2022.10.00')
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3'

implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1'
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'androidx.navigation:navigation-compose:2.6.0'
implementation 'io.coil-kt:coil-compose:2.4.0'

// Hilt
implementation 'com.google.dagger:hilt-android:2.46.1'
kapt 'com.google.dagger:hilt-android-compiler:2.46.1'
implementation("androidx.hilt:hilt-work:1.0.0")
kapt("androidx.hilt:hilt-compiler:1.0.0")
implementation("androidx.work:work-runtime-ktx:2.8.1")
implementation("androidx.hilt:hilt-navigation-compose:1.0.0")

// For instrumentation tests
androidTestImplementation  'com.google.dagger:hilt-android-testing:2.46.1'
kaptAndroidTest 'com.google.dagger:hilt-compiler:2.46.1'

// For local unit tests
testImplementation 'com.google.dagger:hilt-android-testing:2.46.1'
kaptTest 'com.google.dagger:hilt-compiler:2.46.1'

Any help is greatly appreciated.

0

There are 0 best solutions below