hay there hope you doing good so I've been trying to implement a test for my room data base in AndroidTest directory
here is the test i have implemented :
@RunWith(AndroidJUnit4::class)
@SmallTest
class ShoppingDaoTest {
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
private lateinit var database: ShoppingItemDatabase
private lateinit var dao: ShoppingDao
@Before
fun setup() {
database = Room.inMemoryDatabaseBuilder(
ApplicationProvider.getApplicationContext(),
ShoppingItemDatabase::class.java
).allowMainThreadQueries().build()
dao = database.shoppingDao()
}
@After
fun teardown() {
database.close()
}
@Test
fun insertShoppingItem() = runTest {
val shoppingItem = ShoppingItem("name", 1, 1f, "url", id = 1)
dao.insertShoppingItem(shoppingItem)
val allShoppingItems = dao.observeAllShoppingItems().getOrAwaitValue()
assertThat(allShoppingItems).contains(shoppingItem)
}
}
my Dao :
@Dao
interface ShoppingDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertShoppingItem(shoppingItem: ShoppingItem)
@Delete
suspend fun deleteShoppingItem(shoppingItem: ShoppingItem)
@Update
suspend fun updateShoppingItem(shoppingItem: ShoppingItem)
@Query("SELECT * FROM `shopping-items`")
fun observeAllShoppingItems(): LiveData<List<ShoppingItem>>
@Query("SELECT SUM(price * amount) FROM `shopping-items`")
fun observeTotalPrice(): LiveData<Float>
}
my Database Class :
@Database(entities = [ShoppingItem::class], version = 1, exportSchema = false)
abstract class ShoppingItemDatabase:RoomDatabase() {
abstract fun shoppingDao():ShoppingDao
}
the Entity:
@Entity(tableName = "shopping-items")
data class ShoppingItem(
var name: String,
var amount: Int,
var price: Float,
var imageUrl: String,
@PrimaryKey(autoGenerate = true)
val id: Int? = null
)
getOrAwaitValue function :
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
fun <T> LiveData<T>.getOrAwaitValue(
time: Long = 2,
timeUnit: TimeUnit = TimeUnit.SECONDS,
afterObserve: () -> Unit = {}
): T {
var data: T? = null
val latch = CountDownLatch(1)
val observer = object : Observer<T> {
override fun onChanged(o: T) {
data = o
latch.countDown()
[email protected](this)
}
}
this.observeForever(observer)
try {
afterObserve.invoke()
// Don't wait indefinitely if the LiveData is not set.
if (!latch.await(time, timeUnit)) {
throw TimeoutException("LiveData value was never set.")
}
} finally {
this.removeObserver(observer)
}
@Suppress("UNCHECKED_CAST")
return data as T
}
When i run this code the result is an error
java.lang.IllegalStateException:Cannot invoke observeForever on a background thread
the full log if needed :
12-15 13:27:40.065 12955 12978 I TestRunner: started: observeTotalPriceSum(com.example.myshoppinglist.data.local.ShoppingDaoTest)
12-15 13:27:40.213 12955 12978 E TestRunner: failed: observeTotalPriceSum(com.example.myshoppinglist.data.local.ShoppingDaoTest)
12-15 13:27:40.213 12955 12978 E TestRunner: ----- begin exception -----
12-15 13:27:40.215 12955 12978 E TestRunner: java.lang.IllegalStateException: Cannot invoke observeForever on a background thread
12-15 13:27:40.215 12955 12978 E TestRunner: at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:502)
12-15 13:27:40.215 12955 12978 E TestRunner: at androidx.lifecycle.LiveData.observeForever(LiveData.java:224)
12-15 13:27:40.215 12955 12978 E TestRunner: at com.example.myshoppinglist.LiveDataUtilAndroidTestKt.getOrAwaitValue(LiveDataUtilAndroidTest.kt:47)
12-15 13:27:40.215 12955 12978 E TestRunner: at com.example.myshoppinglist.LiveDataUtilAndroidTestKt.getOrAwaitValue$default(LiveDataUtilAndroidTest.kt:33)
12-15 13:27:40.215 12955 12978 E TestRunner: at com.example.myshoppinglist.data.local.ShoppingDaoTest$observeTotalPriceSum$1.invokeSuspend(ShoppingDaoTest.kt:76)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.test.TestDispatcher.processEvent$kotlinx_coroutines_test(TestDispatcher.kt:28)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.test.TestCoroutineScheduler.tryRunNextTaskUnless$kotlinx_coroutines_test(TestCoroutineScheduler.kt:103)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt$runTest$2$1$workRunner$1.invokeSuspend(TestBuilders.kt:320)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:280)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source:1)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source:1)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.test.TestBuildersJvmKt.createTestResult(TestBuildersJvm.kt:13)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0(TestBuilders.kt:308)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0(Unknown Source:1)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0(TestBuilders.kt:166)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0(Unknown Source:1)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0$default(TestBuilders.kt:158)
12-15 13:27:40.215 12955 12978 E TestRunner: at kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0$default(Unknown Source:1)
12-15 13:27:40.215 12955 12978 E TestRunner: at com.example.myshoppinglist.data.local.ShoppingDaoTest.observeTotalPriceSum(ShoppingDaoTest.kt:68)
12-15 13:27:40.215 12955 12978 E TestRunner: at java.lang.reflect.Method.invoke(Native Method)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
12-15 13:27:40.215 12955 12978 E TestRunner: at androidx.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:80)
12-15 13:27:40.215 12955 12978 E TestRunner: at androidx.test.internal.runner.junit4.statement.RunAfters.evaluate(RunAfters.java:61)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:61)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
12-15 13:27:40.215 12955 12978 E TestRunner: at androidx.test.ext.junit.runners.AndroidJUnit4.run(AndroidJUnit4.java:162)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.Suite.runChild(Suite.java:128)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.Suite.runChild(Suite.java:27)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
12-15 13:27:40.215 12955 12978 E TestRunner: at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
12-15 13:27:40.215 12955 12978 E TestRunner: at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:67)
12-15 13:27:40.215 12955 12978 E TestRunner: at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:58)
12-15 13:27:40.215 12955 12978 E TestRunner: at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:446)
12-15 13:27:40.215 12955 12978 E TestRunner: at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2402)
12-15 13:27:40.215 12955 12978 E TestRunner: ----- end exception -----
12-15 13:27:40.220 12955 12978 I TestRunner: finished: observeTotalPriceSum(com.example.myshoppinglist.data.local.ShoppingDaoTest)
java.lang.IllegalStateException: Cannot invoke observeForever on a background thread
at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:502)
at androidx.lifecycle.LiveData.observeForever(LiveData.java:224)
at com.example.myshoppinglist.LiveDataUtilAndroidTestKt.getOrAwaitValue(LiveDataUtilAndroidTest.kt:47)
at com.example.myshoppinglist.LiveDataUtilAndroidTestKt.getOrAwaitValue$default(LiveDataUtilAndroidTest.kt:33)
at com.example.myshoppinglist.data.local.ShoppingDaoTest$observeTotalPriceSum$1.invokeSuspend(ShoppingDaoTest.kt:76)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.test.TestDispatcher.processEvent$kotlinx_coroutines_test(TestDispatcher.kt:28)
at kotlinx.coroutines.test.TestCoroutineScheduler.tryRunNextTaskUnless$kotlinx_coroutines_test(TestCoroutineScheduler.kt:103)
at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt$runTest$2$1$workRunner$1.invokeSuspend(TestBuilders.kt:320)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:280)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source:1)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source:1)
at kotlinx.coroutines.test.TestBuildersJvmKt.createTestResult(TestBuildersJvm.kt:13)
at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0(TestBuilders.kt:308)
at kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0(Unknown Source:1)
at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0(TestBuilders.kt:166)
at kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0(Unknown Source:1)
at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest-8Mi8wO0$default(TestBuilders.kt:158)
at kotlinx.coroutines.test.TestBuildersKt.runTest-8Mi8wO0$default(Unknown Source:1)
at com.example.myshoppinglist.data.local.ShoppingDaoTest.observeTotalPriceSum(ShoppingDaoTest.kt:68)
and the dependency I'm Using in case you need it :
// Room
val room_version = "2.6.1"
implementation("androidx.room:room-runtime:$room_version")
kapt("androidx.room:room-compiler:$room_version")
implementation("androidx.room:room-ktx:$room_version")
testImplementation("androidx.room:room-testing:$room_version")
// coroutines
val coroutines_version = "1.7.1"
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version")
androidTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version")
// Google Truth Library
androidTestImplementation("com.google.truth:truth:1.1.4")
testImplementation("com.google.truth:truth:1.1.4")
// test Imp
testImplementation("android.arch.core:core-testing:1.1.1")
androidTestImplementation("android.arch.core:core-testing:1.1.1")
I've tried fixing it by adding the following line :
var instantTaskExecutorRule = InstantTaskExecutorRule()
if i remove it the error changes to this :
java.lang.IllegalStateException: This job has not completed
is there something I'm missing ? how can i fix this problem ?