-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Inject the right database in instrumentation unit test #719
Description
I was trying to run PlantDetailViewModelTest but I found there is something going wrong.
In the test, you try to initialize appDatabase in the test while it should be injected.
Is it a problem or bad practice?
It is actually a big problem, if we define an in-memory database in our test, and inject the repository (plantRepository & gardenPlantRepository) that've been provided by Hilt we will have two different database to work on. First our defined in-memory database, second the actual database in our installed-app that've been injected into our repositories, and so passed to viewModel object.
So, the assertion in the test is not valid, because we try to run it against in-app database not the in-memory instance.
How can we make this test fail?
Simply install the app on the emulator, add Apple planet to our garden. Then change the planetId of our test object to malus-pumila (which is the planet_id for Apple planet in app's database), and deploy the test on the same emulator. It will fail.
If our viewModel tries to modify or insert any object to the database it will modify the app database not our testable in-memory database.
What is the solution?
I thing we should replace our DatabaseModule with some fake hilt module like this one:
@Module
@TestInstallIn(
components = [SingletonComponent::class],
replaces = [DatabaseModule::class],
)
class FakeDatabaseModule {
@Singleton
@Provides
fun provideAppDatabase(@ApplicationContext context: Context): AppDatabase {
// I think injecting ApplicationContext is fine while we are using instrumentation test.
return Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java).build()
}
...
}And in our test we can simply inject the database object if we have to deal with it (close it maybe).
@Inject
lateinit var appDatabase: AppDatabaseNow our viewModel test will work on a single in-memory database.