iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 22
0

這篇會替Day21 ROOM -2 (番外)補上測試

首先新增
WordDaoTest在 androidTest底下
先做前置作業
WordDaoTest.kt

@RunWith(AndroidJUnit4::class)
class WordDaoTest {

 val instantTaskExecutorRule = InstantTaskExecutorRule()
   private lateinit var wordDao: WordDao
   private lateinit var db: WordRoomDatabase
...
}

每次運行tests前要先創建DB
執行完後close DB

WordDaoTest.kt

class WordDaoTest {
...
@Before
   fun createDb() {
       val context = InstrumentationRegistry.getTargetContext()
       //將db存在內存 當process結束時會清除
       db = Room.inMemoryDatabaseBuilder(context, WordRoomDatabase::class.java)
           // 允許在主線程查詢 僅用於測試
           .allowMainThreadQueries()
           .build()
       wordDao = db.wordDao()
   }
}
每次執行完後清除
class WordDaoTest {
... 
  @After
   fun closeDb() {
       db.close()
   }
}

其中
instantTaskExecutorRule 用途是為了避免 java.lang.IllegalStateException: Cannot invoke observeForever on a background thread
錯誤

接著開始撰寫測試案例

WordDaoTest.kt

@Test
fun insertAndGetWord() = runBlocking {
   val word = WordEntity("word")
   wordDao.insert(word)
   val allWords = wordDao.getAllWords()
   Assert.assertEquals(allWords?.value?.get(0), word.word)
}

然後運行
此時結果應該會是fail的
原因是LiveData不是即時更新的
所以照著運行下來時allWords的數據還沒更新 是null
所以失敗

接著要寫一個擴展來等待數據更新
之後驗證資料是否正確

代碼如下
LiveDataTestUtil.kt

@Throws(InterruptedException::class)
fun <T> LiveData<T>.waitForValue(): T {
   val data = arrayOfNulls<Any>(1)
   val latch = CountDownLatch(1)
   val observer = object : Observer<T> {
       override fun onChanged(o: T?) {
           data[0] = o
           latch.countDown()
           this@waitForValue.removeObserver(this)
       }
   }
   this.observeForever(observer)
   latch.await(2, TimeUnit.SECONDS)

   return data[0] as T
}

這段擴展會等待兩秒直到liveData回調

WordDaoTest完整代碼如下

WordDaoTest.kt

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.room.Room
import androidx.test.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
import com.ithome11.jetpackmvvmdemo.util.WordDao
import com.ithome11.jetpackmvvmdemo.util.WordEntity
import com.ithome11.jetpackmvvmdemo.util.WordRoomDatabase
import junit.framework.Assert
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith


@RunWith(AndroidJUnit4::class)
class WordDaoTest {

   //立即調用線程的背景操作
   @get:Rule
   val instantTaskExecutorRule = InstantTaskExecutorRule()
   private lateinit var wordDao: WordDao
   private lateinit var db: WordRoomDatabase

   @Before
   fun createDb() {
       val context = InstrumentationRegistry.getTargetContext()
       //將db存在內存 當process結束時會清除
       db = Room.inMemoryDatabaseBuilder(context, WordRoomDatabase::class.java)
           // 允許在主線程查詢 僅用於測試
           .allowMainThreadQueries()
           .build()
       wordDao = db.wordDao()
   }

   @After
   fun closeDb() {
       db.close()
   }

   @Test
   fun insertAndGetWord() = runBlocking {
       val word = WordEntity("word")
       wordDao.insert(word)
       val allWords = wordDao.getAllWords().waitForValue()
       Assert.assertEquals(allWords[0].word, word.word)
   }

   @Test
   fun getAllWords() = runBlocking {
       val word = WordEntity("aaa")
       wordDao.insert(word)
       val word2 = WordEntity("bbb")
       wordDao.insert(word2)
       val allWords = wordDao.getAllWords().waitForValue()
       Assert.assertEquals(allWords[0].word, word.word)
       Assert.assertEquals(allWords[1].word, word2.word)
   }

   @Test
   fun deleteAll() = runBlocking {
       val word = WordEntity("word")
       wordDao.insert(word)
       val word2 = WordEntity("word2")
       wordDao.insert(word2)
       wordDao.deleteAll()
       val allWords = wordDao.getAllWords().waitForValue()
       Assert.assertTrue(allWords.isEmpty())
   }
}

最後貼上solution
https://github.com/mars1120/jetpackMvvmDemo/tree/room


上一篇
Day21 ROOM -2 (番外)
下一篇
Day23 call API & tests
系列文
Android × CI/CD 如何用基本的MVVM專案實現 CI/CD 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言