I'm trying to test Room Database. For this I need an in memory instance of database. I'm using hilt for DI.
So, i have an app Module in app package:
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Singleton
@Provides
fun provideDatabase(
@ApplicationContext context: Context,
) = Room.databaseBuilder(
context.applicationContext,
UserDatabase::class.java,
"user"
).build()
@Singleton
@Provides
fun provideDao(db: UserDatabase) = db.getUserDao()
}
I have created TestRunner for Hilt and also added it in gradle.
class HiltTestRunner : AndroidJUnitRunner() {
override fun newApplication(
cl: ClassLoader?,
className: String?,
context: Context?,
): Application {
return super.newApplication(cl, HiltTestApplication::class.java.name, context)
}
}
Here is gradle
defaultConfig {
applicationId "package"
minSdk 24
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner = "package.HiltTestRunner"
}
Here is my TestAppModule
@Module
@TestInstallIn(
components = [SingletonComponent::class],
replaces = [AppModule::class]
)
object TestAppModule {
@Provides
fun provideInMemoryDb(@ApplicationContext context: Context) =
Room.inMemoryDatabaseBuilder(
context,
UserDatabase::class.java
).allowMainThreadQueries().build()
}
And my test class
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@HiltAndroidTest
class UserDaoTest {
@get:Rule
var instantExecutorRule = InstantTaskExecutorRule()
@get:Rule
var hiltRule = HiltAndroidRule(this)
@Inject
lateinit var database: UserDatabase
private lateinit var dao: UserDao
@Before
fun setup() {
hiltRule.inject()
dao = database.getUserDao()
}
@Test
fun insertUser() {
runTest {
val user = User(0, "login", "", "", "", 1)
dao.saveUser(user)
val dbUser = dao.getUser()
assertThat(dbUser, equalTo(user))
}
}
}
So, when I run the test I'm getting the error that UserDao cannot be provided without @Provides, but i'm not even injecting it in my test class. Can anyone please clarify this?
I noticed that it works just fine if change my TestAppModule like that:
@Module
@InstallIn(SingletonComponent::class)
object TestAppModule {
@Provides
@Named("test_db")
fun provideInMemoryDb(@ApplicationContext context: Context) =
Room.inMemoryDatabaseBuilder(
context,
UserDatabase::class.java
).allowMainThreadQueries().build()
}
Basically, here I'm not using TestInstallIn and added a named annotation to function.