5.17
5. 测试您的数据库
之前的 Codelab 讨论了测试代码的重要性。在此任务中,您将添加一些单元测试来测试 DAO 查询,然后按照此 Codelab 的步骤继续操作时,还将添加更多测试。
如需测试数据库实现,推荐的方法是编写在 Android 设备上运行的 JUnit 测试。由于执行这些测试不需要创建 activity,因此它们的执行速度比界面测试速度快。
- 在 build.gradle.kts (Module :app)文件中,请注意 Espresso 和 JUnit 的以下依赖项。
// Testing
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
- 切换到 Project 视图,然后右键点击 src > New > Directory,以便为测试创建测试源代码集。

- 从 New Directory 弹出式窗口中选择 androidTest/kotlin。

- 创建一个名为 ItemDaoTest.kt的 Kotlin 类。
- 为 ItemDaoTest类添加@RunWith(AndroidJUnit4::class)注解。现在,您的类如以下示例代码所示:
package com.example.inventory
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class ItemDaoTest {
}
- 在类内,添加 ItemDao和InventoryDatabase类型的私有var变量。
import com.example.inventory.data.InventoryDatabase
import com.example.inventory.data.ItemDao
private lateinit var itemDao: ItemDao
private lateinit var inventoryDatabase: InventoryDatabase
- 添加一个函数以创建数据库,并为其添加 @Before注解,以便在每次测试之前能够运行该数据库。
- 在该方法内,初始化 itemDao。
import android.content.Context
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import org.junit.Before
@Before
fun createDb() {
    val context: Context = ApplicationProvider.getApplicationContext()
    // Using an in-memory database because the information stored here disappears when the
    // process is killed.
    inventoryDatabase = Room.inMemoryDatabaseBuilder(context, InventoryDatabase::class.java)
        // Allowing main thread queries, just for testing.
        .allowMainThreadQueries()
        .build()
    itemDao = inventoryDatabase.itemDao()
}
在此函数中,您将使用内存中的数据库,但不将该数据库保留在磁盘上。为此,您可以使用 inMemoryDatabaseBuilder() 函数。这样做的原因是,信息不需要保留,而是需要随着进程终止而被删除。您是在 .allowMainThreadQueries() 主线程中运行 DAO 查询,专门用于测试。
- 添加其他函数以关闭数据库。然后为该函数添加 @After注解,以在每次测试后运行该函数来关闭数据库。
import org.junit.After
import java.io.IOException
@After
@Throws(IOException::class)
fun closeDb() {
    inventoryDatabase.close()
}
- 在类 ItemDaoTest中声明数据库要使用的商品,如以下代码示例所示:
import com.example.inventory.data.Item
private var item1 = Item(1, "Apples", 10.0, 20)
private var item2 = Item(2, "Bananas", 15.0, 97)
- 添加实用函数,先向数据库中添加一个商品,然后添加两个商品。稍后,您将在测试中使用这些函数。将它们标记为 suspend,以便它们可以在协程中运行。
private suspend fun addOneItemToDb() {
    itemDao.insert(item1)
}
private suspend fun addTwoItemsToDb() {
    itemDao.insert(item1)
    itemDao.insert(item2)
}
- 为向数据库中插入单个商品的 insert()编写测试。将测试命名为daoInsert_insertsItemIntoDB,并为其添加@Test注解。
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Test
@Test
@Throws(Exception::class)
fun daoInsert_insertsItemIntoDB() = runBlocking {
    addOneItemToDb()
    val allItems = itemDao.getAllItems().first()
    assertEquals(allItems[0], item1)
}
在此测试中,您将使用实用函数 addOneItemToDb() 向数据库中添加一个商品。然后,读取数据库中的第一个商品。通过 assertEquals(),您可以将预期值与实际值进行比较。您将使用 runBlocking{} 在新的协程中运行测试。此设置是将实用函数标记为 suspend 的原因。
- 运行测试并确保测试通过。


- 为数据库中的 getAllItems()编写另一个测试。将测试命名为daoGetAllItems_returnsAllItemsFromDB。
@Test
@Throws(Exception::class)
fun daoGetAllItems_returnsAllItemsFromDB() = runBlocking {
    addTwoItemsToDb()
    val allItems = itemDao.getAllItems().first()
    assertEquals(allItems[0], item1)
    assertEquals(allItems[1], item2)
}
在上述测试中,您在协程内向数据库中添加了两个商品。然后,您读取了这两个商品,并将其与预期值进行比较。
 
                    
                 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号