Android Hilt Testing: Bind different database per test

Viewed 415

I am currently writing tests for my Android application using Hilt. The App got a Room database, which I want to use in my test classes. Furthermore, I want in some test classes an empty database and in others a database with test values. My question is if I can define in my Test, which provider (empty/full DB) is used for all injections that are happening in the test class?

I tried using the @Named annotation, Qualifiers, and @BindValue. With the first two I am able to use the correct provider for my database, but I do not know how this could be used when injecting my repository. With @BindValue I am not sure if this can be used for this at all.

Here is some simplified code of my problem:

TestDatabaseModule:

@Module
@TestInstallIn(components = SingletonComponent.class, replaces = DatabaseModule.class)
public class TestDatabaseModule {
    
    // Provide empty DB
    @Singleton
    @Provides
    AppDatabase provideInMemoryDbEmpty(@ApplicationContext Context context) {
        return Room.inMemoryDatabaseBuilder(context, AppDatabase.class).build();
    }
    
    // Provide populated DB
    @Singleton
    @Provides
    AppDatabase provideInMemoryDbFull(@ApplicationContext Context context, Provider<AppDatabase> databaseProvider) {
        // AppDatabasePopulateCallback adds some test data
        return Room.inMemoryDatabaseBuilder(context, AppDatabase.class).addCallback(new AppDatabasePopulateCallback(databaseProvider)).build();
    }
}

Module providing DAO and repository

@InstallIn(SingletonComponent.class)
@Module
public class AccessModule {

    @Singleton
    @Provides
    MyDao provideMyDao(AppDatabase appDatabase) {
        return appDatabase.myDao();
    }

    @Provides
    MyRepository providesMyRepository(MyDao myDao) {
        return new MyRepository(myDao);
    }
}

Test Class one:

@HiltAndroidTest
@SmallTest
public class TestOne {

    @Rule
    public HiltAndroidRule hiltRule = new HiltAndroidRule(this);

    @Rule
    public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule();


    // Inject repository that uses empty DB
    @Inject
    MyRepository myRepository;

    @Before
    public void createDb() {
        hiltRule.inject();
    }

    @Test
    public void testOne() {
        // Use my repository with the empty database
    }

Test class two:

@HiltAndroidTest
@SmallTest
public class TestTwo {

    @Rule
    public HiltAndroidRule hiltRule = new HiltAndroidRule(this);

    @Rule
    public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule();


    // Inject repository that uses populated DB
    @Inject
    MyRepository myRepository;

    @Before
    public void createDb() {
        hiltRule.inject();
    }

    @Test
    public void testTwo() {
        // Use my repository with the full database
    }

So in the TestOne class, I want to use the repository that can access the empty database, and in the TestTwo class the repository that uses the database with test data.

I know I could populate the database in every test I want to use the data. That is what I will do if it is not possible with Hilt. I am glad for any advice to solve my problem or someone answering that I am on the wrong track if it is not possible.

Thank you!

0 Answers
Related