Android Room test with Hilt: UserDao cannot be provided without an @Provides-annotated method

Viewed 316

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.

0 Answers
Related