tezvyn:

Explain integration tests and isolate Room DAO tests

Curated by the Tezvyn teamSource: developer.android.comintermediate
Explain integration tests and isolate Room DAO tests

Tests integration vs unit testing and Room isolation. Outline: verify real DAO-to-DB interaction with Room.inMemoryDatabaseBuilder; reset state by closing and recreating the DB in @After. Red flag: mocking the DAO or using an on-disk database.

WHAT THIS TESTS: This question probes three senior-level competencies. First, do you understand the boundary between unit tests, which validate logic in isolation with mocked dependencies, and integration tests, which exercise real component interaction? Second, do you know Room's specific testing affordances, particularly the in-memory database builder and the requirement for an Android environment? Third, do you treat test data as mutable shared state that must be reset to guarantee hermetic, order-independent test execution?

A GOOD ANSWER COVERS: Four specific elements in order. First, define the purpose of an integration test as verifying that the DAO, Room, and SQLite actually work together to persist and query data correctly, catching issues like type converter mismatches or migration bugs that unit tests miss. Second, state that you use Room.inMemoryDatabaseBuilder to create a non-persistent database that lives only for the test process, avoiding disk I/O side effects and simplifying cleanup. Third, note that these tests run on an Android environment, either on an emulator or device using AndroidJUnit4, or on the JVM with Robolectric, because Room needs the Android SQLite stack. Fourth, explain isolation by closing the database and recreating it in an @After method, or by using a fresh database instance per test, ensuring that inserts from one test never leak into another.

COMMON WRONG ANSWERS: Three red flags stand out. One, suggesting you mock the DAO or the database entirely, which collapses the integration test back into a unit test and defeats the purpose. Two, using a persistent on-disk database file without cleanup, which creates flaky ordering dependencies between tests. Three, proposing to manually delete rows with DAO methods instead of destroying the database instance, which is slower, riskier, and can fail if foreign key constraints or triggers are involved.

LIKELY FOLLOW-UPS: An interviewer might push on migration testing, asking how you would verify that a schema change does not lose user data. They could ask about testing with a Provider or Repository pattern, where you must decide whether to test the DAO directly or through the abstraction layer. They might also ask how to handle coroutines or RxJava streams in these tests, expecting you to use runTest or InstantTaskExecutorRule to make asynchronous Room operations synchronous for deterministic assertions.

ONE CONCRETE EXAMPLE: Suppose you have a UserDao with an insert and a getUserById method. In your test class annotated with @HiltAndroidTest or @RunWith AndroidJUnit4 class, you declare a private lateinit var db AppDatabase. In @Before, you initialize it with Room.inMemoryDatabaseBuilder ApplicationProvider.getApplicationContext AppDatabase::class.java build, and you obtain the DAO with db.userDao. In @After, you call db.close. Each test then creates its own seed data, calls the DAO methods, and asserts against the returned objects. Because the database is in memory and recreated for every test, test A inserting a user with ID one cannot interfere with test B asserting that ID one does not exist.

Read the original → developer.android.com

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.