2

I want to have the real ViewModel injected into my composable. This question's answer is stating how to mock the injected view model which is not what I want.

My composable is receiving the view model like this:

fun YourDetailsScreen(viewModel: YourDetailsViewModel = viewModel()) {

The viewModel() method is the inline function provided by the androidx.lifecycle.viewmodel.compose package.

As far as I'm aware, I have implemented the custom test runner, my instrumentation test is configured correctly with the @HiltAndroidTest and the HiltAndroidRule wrapping my composeTestRule like so:

@get:Rule
val rule: RuleChain = RuleChain.outerRule(hiltAndroidRule)
   .around(composeTestRule)

When I launch my composable, I get the following exception:

Caused by: java.lang.InstantiationException: java.lang.Class<com.zzz.feature.onboarding.registration.yourdetails.YourDetailsViewModel> has no zero argument constructor

Here is my ViewModel's constructor.

@HiltViewModel
class YourDetailsViewModel @Inject constructor(
    private val isFirstNameValidUseCase: IsFirstNameValidUseCase,
    private val isLastNameValidUseCase: IsLastNameValidUseCase,
    private val isPhoneNumberValidUseCase: IsPhoneNumberValidUseCase
) : ViewModel()

Everything is injected fine when running the app, I just can't get it to work in my android tests!

StuStirling
  • 15,601
  • 23
  • 93
  • 150
  • I'm facing the exact same issue! Did you find a solution for this? Thanks in advance! – amp Jun 02 '22 at 13:51

1 Answers1

2

After some hours of debugging, found the issue.

Basically, the main problem was that I was using createComposeRule() instead of createAndroidComposeRule<MyActivity>(), so the HiltViewModelFactory was not used.

After I started using createAndroidComposeRule<MyActivity>() as follow, my test started running:

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

    val hiltRule = HiltAndroidRule(this)

    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @get:Rule
    val rule: RuleChain = RuleChain.outerRule(hiltRule)
        .around(composeTestRule)

    // Tests....
}

(MyActivity must be annotated with @AndroidEntryPoint)

amp
  • 11,754
  • 18
  • 77
  • 133
  • I guess the best option here would be to create a new TestActivity class with the annotation but no `setContent` so you can test whatever composable you want. – darnmason Aug 25 '23 at 04:23