I'm trying to test the following LocalDataSource function, NameLocalData.methodThatFreezes function, but it freezes. How can I solve this? Or How can I test it in another way?
Class to be tested
class NameLocalData(private val roomDatabase: RoomDatabase) : NameLocalDataSource {
override suspend fun methodThatFreezes(someParameter: Something): Something {
roomDatabase.withTransaction {
try {
// calling room DAO methods here
} catch(e: SQLiteConstraintException) {
// ...
}
return something
}
}
}
Test class
@MediumTest
@RunWith(AndroidJUnit4::class)
class NameLocalDataTest {
private lateinit var nameLocalData: NameLocalData
// creates a Room database in memory
@get:Rule
var roomDatabaseRule = RoomDatabaseRule()
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
@Before
fun setup() = runBlockingTest {
initializesSomeData()
nameLocalData = NameLocalData(roomDatabaseRule.db)
}
@Test
fun methodThatFreezes() = runBlockingTest {
nameLocalData.methodThatFreezes // test freezes
}
// ... others NameLocalDataTest tests where those functions been tested does not use
// roomDatabase.withTransaction { }
}
Gradle's files configuration
espresso_version = '3.2.0'
kotlin_coroutines_version = '1.3.3'
room_version = '2.2.5'
test_arch_core_testing = '2.1.0'
test_ext_junit_version = '1.1.1'
test_roboletric = '4.3.1'
test_runner_version = '1.2.0'
androidTestImplementation "androidx.arch.core:core-testing:$test_arch_core_testing"
androidTestImplementation "androidx.test.espresso:espresso-core:$espresso_version"
androidTestImplementation "androidx.test.ext:junit:$test_ext_junit_version"
androidTestImplementation "androidx.test:rules:$test_runner_version"
androidTestImplementation "androidx.test:runner:$test_runner_version"
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlin_coroutines_version"
Last time I wrote a test for Room database I just simply use runBlock
and it worked for me...
Could you take a look into this sample and check if it works for you as well?
Edit: Ops! I missed this part... I tried this (in the same sample):
@Transaction
@Transaction
suspend fun quickInsert(book: Book) {
save(book)
delete(book)
}
setTransactionExecutor
to your Database instantiation.appDatabase = Room.inMemoryDatabaseBuilder(
InstrumentationRegistry.getInstrumentation().context,
AppDatabase::class.java
).setTransactionExecutor(Executors.newSingleThreadExecutor())
.build()
runBlocking
@Test
fun dummyTest() = runBlocking {
val dao = appDatabase.bookDao();
val id = dummyBook.id
dao.quickInsert(dummyBook)
val book = dao.bookById(id).first()
assertNull(book)
}
See this question.
I had tried many things to make this work, used runBlockingTest
, used TestCoroutineScope
, tried runBlocking
, used allowMainThreadQueries
, setTransactionExecutor
, and setQueryExecutor
on my in memory database.
But nothing worked until I found this comment thread in the Threading models in Coroutines and Android SQLite API
article in the Android Developers Medium blog, other people mentioned running into this. Author Daniel Santiago said:
I’m not sure what Robolectric might be doing under the hood that could cause withTransaction to never return. We usually don’t have Robolectric tests but we have plenty of Android Test examples if you want to try that route: https://android.googlesource.com/platform/frameworks/support/+/androidx-master-dev/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/SuspendingQueryTest.kt
I was able to fix my test by changing it from a Robolectric test to an AndroidTest and by using runBlocking
This is an example from the google source:
@Before
@Throws(Exception::class)
fun setUp() {
database = Room.inMemoryDatabaseBuilder(
ApplicationProvider.getApplicationContext(),
TestDatabase::class.java
)
.build()
booksDao = database.booksDao()
}
@Test
fun runSuspendingTransaction() {
runBlocking {
database.withTransaction {
booksDao.insertPublisherSuspend(
TestUtil.PUBLISHER.publisherId,
TestUtil.PUBLISHER.name
)
booksDao.insertBookSuspend(TestUtil.BOOK_1.copy(salesCnt = 0))
booksDao.insertBookSuspend(TestUtil.BOOK_2)
booksDao.deleteUnsoldBooks()
}
assertThat(booksDao.getBooksSuspend())
.isEqualTo(listOf(TestUtil.BOOK_2))
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With