Closed sheiapp closed 2 years ago
The error message says you're missing a binding for RandomUserRepository
. Do you provide one?
Hi @bcorso
RandomUserRepositoryImplTest - This class is an fake implementations of RandomUserRepository interface.
my idea to mock this fake object in the test class. So that i can mock the its behavior accordingly.
Thank you
Dagger does not know that RandomUserRepositoryImplTest
is an implementation of RandomUserRepository
unless you tell it. Rather than using @BindValue
you should just use a normal nested module:
@HiltAndroidTest
@UninstallModules(AppModule::class)
@RunWith(AndroidJUnit4::class)
class RandomUserListFragmentTest {
@Module
@InstallIn(SingletonComponent::class)
interface TestModule {
// Bind the implementation to the interface.
@Binds fun bind(impl: RandomUserRepositoryImplTest): RandomUserRepository
companion object {
@Provides
@Singleton
fun provideImpl(): RandomUserRepositoryImplTest = mock()
}
}
@Inject lateinit var glideRequestManager: RequestManager
@Inject lateinit var mockRandomUserRepository: RandomUserRepositoryImplTest
// ...
}
Edit: Added @Singleton
to the mock binding, as that will likely need to be scoped if you do any sort of setup with the mock instance in your test.
Hi @bcorso
I tried with this code snippet
@HiltAndroidTest
@UninstallModules(AppModule::class)
@RunWith(AndroidJUnit4::class)
class RandomUserListFragmentTest {
@get:Rule
val hiltRule = HiltAndroidRule(this)
@Inject
lateinit var glideRequestManager: RequestManager
@Before
fun launchFragment() {
hiltRule.inject()
}
@Module
@InstallIn(SingletonComponent::class)
interface TestModule {
@Binds fun bind(impl: RandomUserRepositoryImplTest): RandomUserRepository
companion object {
@Provides
@Singleton
fun provideImpl(): RandomUserRepositoryImplTest = mock()
}
}
@Inject
lateinit var repository: RandomUserRepositoryImplTest
@Test
fun testTheLoadingStateOfTheFragmentAfterGettingTheData() {
whenever(repository.getRandomUserList())
.doReturn(flowOf(PagingData.from(emptyList())))
ActivityScenario.launch(RandomUserActivity::class.java)
Espresso.onView(ViewMatchers.withId(R.id.recyclerView))
.check { view, noViewFoundException ->
if (noViewFoundException != null) {
throw noViewFoundException
}
val recyclerView = view as RecyclerView
Assert.assertEquals(0, recyclerView.adapter?.itemCount)
}
}
still Iam getting error like /Users/shaheer/AndroidStudioProjects/ss/app/build/generated/hilt/component_sources/debugAndroidTest/com/ss/assignment/ui/random_user_ui/RandomUserActivityTest_TestComponentDataSupplier.java:8: error: cannot find symbol import dagger.hilt.android.internal.testing.root.DaggerRandomUserActivityTest_HiltComponents_SingletonC; ^ symbol: class DaggerRandomUserActivityTest_HiltComponents_SingletonC location: package dagger.hilt.android.internal.testing.root
and /Users/shaheer/AndroidStudioProjects/ss/app/build/generated/hilt/component_sources/debugAndroidTest/dagger/hilt/android/internal/testing/root/RandomUserActivityTest_HiltComponents.java:133: error: [Dagger/MissingBinding] com.ss.assignment.data.repository.RandomUserRepository cannot be provided without an @Provides-annotated method. public abstract static class SingletonC implements SunAndSandsApp_GeneratedInjector, ^ com.ss.assignment.data.repository.RandomUserRepository is injected at com.ss.assignment.ui.random_user_ui.RandomUserSharedViewModel(randomUserRepository) com.ss.assignment.ui.random_user_ui.RandomUserSharedViewModel is injected at com.ss.assignment.ui.random_user_ui.RandomUserSharedViewModel_HiltModules.BindsModule.binds(arg0) @dagger.hilt.android.internal.lifecycle.HiltViewModelMap java.util.Map<java.lang.String,javax.inject.Provider<androidx.lifecycle.ViewModel>> is requested at dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.ViewModelFactoriesEntryPoint.getHiltViewModelMap() [dagger.hilt.android.internal.testing.root.RandomUserActivityTest_HiltComponents.SingletonC → dagger.hilt.android.internal.testing.root.RandomUserActivityTest_HiltComponents.ActivityRetainedC → dagger.hilt.android.internal.testing.root.RandomUserActivityTest_HiltComponents.ViewModelC]
@Inject lateinit var mockRandomUserRepository: RandomUserRepositoryImplTest.
in the above solution, I saw you suggest to do a field injection but the actual injection is happening in ViewModel.
will it make sense!.
the code implementation is like
@AndroidEntryPoint
class RandomUserListFragment : Fragment(R.layout.fragment_random_user_list) {
private var _binding: FragmentRandomUserListBinding? = null
private val sharedViewModel: RandomUserSharedViewModel by activityViewModels()
@Inject
lateinit var glideRequestManager: RequestManager
...
}
@HiltViewModel
class RandomUserSharedViewModel @Inject constructor( val randomUserRepository: RandomUserRepository) :
ViewModel() {
....
}
so by mocking the repository and injecting it into the viewmodel. I meant to test the behavior of the UI - success response, exception...
Thank you
@sheiapp the entry point from the error message is coming from a component in RandomUserActivityTest
, but the test in your snippet is RandomUserListFragmentTest
. You will have to add the bindings to that test as well (though, if you end up doing this for every test you should also look into @TestInstallIn
).
in the above solution, I saw you suggest to do a field injection but the actual injection is happening in ViewModel. will it make sense!.
It should be fine to inject RandomUserRepositoryImplTest
into your test since the test is providing the binding into the SingletonComponent
.
Thank you so much @bcorso it is working. If you don't mind, I'd like to clear up one last misunderstanding with you. ie, if I do want to use @BindValue then how would be the implementation in this scenario.
ie, if I do want to use @BindValue then how would be the implementation in this scenario.
You would use the nested TestModule
class in the snippet above. (sorry, still not sure that's answering your question)
Ah sorry, I read your previous comment wrong (I thought you said "do not want to use").
If you want to use @BindValue
, you could probably use the module just for the @Binds
. You could try something like this:
@HiltAndroidTest
@UninstallModules(AppModule::class)
@RunWith(AndroidJUnit4::class)
class RandomUserListFragmentTest {
@Module
@InstallIn(SingletonComponent::class)
interface TestModule {
@Binds fun bind(impl: RandomUserRepositoryImplTest): RandomUserRepository
}
@BindValue
@JvmField
val repository: RandomUserRepositoryImplTest = mock()
// ...
}
Thank you so much @bcorso
please check this code. as I am trying to add the repository with @BindValue. the hilt is throwing error as follows.
getting errors like
Hilt version 2.14