Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@HiltViewModel Unit test problem. #4212

Closed
Jaehwa-Noh opened this issue Jan 12, 2024 · 2 comments
Closed

@HiltViewModel Unit test problem. #4212

Jaehwa-Noh opened this issue Jan 12, 2024 · 2 comments

Comments

@Jaehwa-Noh
Copy link

Jaehwa-Noh commented Jan 12, 2024

Hello,
I'm trying to test ViewModel on Unit test.
But, I can't use @Inject on ViewModel. I can't found any documentation about @HiltViewModel Unit test.
How can I test it? Is there any documentation?

I'm using compose.

My ViewModel

@HiltViewModel
class AmphibiansViewModel @Inject constructor(
    val amphibiansInfoRepository: AmphibiansInfoRepository
) : ViewModel() {

    private var _amphibiansUiState: MutableStateFlow<AmphibiansUiState> =
        MutableStateFlow(AmphibiansUiState.Loading)
    val amphibiansUiState: StateFlow<AmphibiansUiState> = _amphibiansUiState.asStateFlow()

    init {
        getAmphibiansList()
    }

    fun getAmphibiansList() {
        viewModelScope.launch {
            _amphibiansUiState.value = AmphibiansUiState.Loading
            _amphibiansUiState.value = try {
                AmphibiansUiState.Success(amphibians = amphibiansInfoRepository.getAmphibiansInfo())
            } catch (e: IOException) {
                AmphibiansUiState.Error(e.localizedMessage ?: "")
            } catch (e: HttpException) {
                AmphibiansUiState.Error(e.localizedMessage ?: "")
            }
        }
    }
}


sealed interface AmphibiansUiState {
    data class Success(val amphibians: List<AmphibiansInfoApiModel>) : AmphibiansUiState
    data class Error(val errorMessage: String) : AmphibiansUiState
    object Loading : AmphibiansUiState
}

And unit test code.

@HiltAndroidTest
class AmphibiansViewModelTest {
    @get:Rule(order = 0)
    val hiltRule = HiltAndroidRule(this)

    @get:Rule(order = 1)
    val testDispatcher = TestDispatcherRule()

    @Inject
    lateinit var amphibiansViewModel: AmphibiansViewModel

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

    @Test
    fun amphibiansViewModel_GetAmphibiansInfo_GetAmphibiansListSuccess() {
        assertEquals(
            AmphibiansUiState.Success(FakeAmphibiansDataSource.getAmphibiansInfo),
            amphibiansViewModel.amphibiansUiState.value
        )
    }
}

This is error message.

error: [dagger.hilt.android.processor.internal.viewmodel.ViewModelValidationPlugin] 
  public abstract static class SingletonC implements AmphibiansApplication_GeneratedInjector,
                         ^
  Injection of an @HiltViewModel class is prohibited since it does not create a ViewModel instance correctly.
  Access the ViewModel via the Android APIs (e.g. ViewModelProvider) instead.
  Injected ViewModel: com.example.myapplication.ui.AmphibiansViewModel
  
      com.example.myapplication.ui.AmphibiansViewModel is injected at
          com.example.myapplication.AmphibiansViewModelTest.amphibiansViewModel
      com.example.myapplication.AmphibiansViewModelTest is injected at
          com.example.myapplication.AmphibiansViewModelTest_GeneratedInjector.injectTest(com.example.myapplication.AmphibiansViewModelTest)
@dmapr
Copy link

dmapr commented Jan 12, 2024

Personally I've always written JVM tests for ViewModels where you just instantiate them normally and only wrote Android tests for components using the VMs — Fragments, Activities, compose functions. Any reason you don't want to write AmphibiansViewModelTest as a JVM test?

@Jaehwa-Noh
Copy link
Author

Thank you. I misunderstand the documentation in Unit test and UI test section.
So I change the code like this, and it works very well.

class AmphibiansViewModelTest {
    @get:Rule
    val testDispatcher = TestDispatcherRule()

    private lateinit var amphibiansViewModel: AmphibiansViewModel

    @Before
    fun injectHiltRule() {
        amphibiansViewModel = AmphibiansViewModel(amphibiansInfoRepository = FakeAmphibiansInfoRepository())
    }

    @Test
    fun amphibiansViewModel_GetAmphibiansInfo_GetAmphibiansListSuccess() {
        assertEquals(
            AmphibiansUiState.Success(FakeAmphibiansDataSource.getAmphibiansInfo),
            amphibiansViewModel.amphibiansUiState.value
        )
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants