5.17

5. 测试您的数据库

之前的 Codelab 讨论了测试代码的重要性。在此任务中,您将添加一些单元测试来测试 DAO 查询,然后按照此 Codelab 的步骤继续操作时,还将添加更多测试。

如需测试数据库实现,推荐的方法是编写在 Android 设备上运行的 JUnit 测试。由于执行这些测试不需要创建 activity,因此它们的执行速度比界面测试速度快。

  1. 在 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")
  1. 切换到 Project 视图,然后右键点击 src > New > Directory,以便为测试创建测试源代码集。

9121189f4a0d2613.png

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

fba4ed57c7589f7f.png

  1. 创建一个名为 ItemDaoTest.kt 的 Kotlin 类。
  2. 为 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 {
}
  1. 在类内,添加 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
  1. 添加一个函数以创建数据库,并为其添加 @Before 注解,以便在每次测试之前能够运行该数据库。
  2. 在该方法内,初始化 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 查询,专门用于测试。

  1. 添加其他函数以关闭数据库。然后为该函数添加 @After 注解,以在每次测试后运行该函数来关闭数据库。
 
import org.junit.After
import java.io.IOException

@After
@Throws(IOException::class)
fun closeDb() {
    inventoryDatabase.close()
}
  1. 在类 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)
  1. 添加实用函数,先向数据库中添加一个商品,然后添加两个商品。稍后,您将在测试中使用这些函数。将它们标记为 suspend,以便它们可以在协程中运行。
 
private suspend fun addOneItemToDb() {
    itemDao.insert(item1)
}

private suspend fun addTwoItemsToDb() {
    itemDao.insert(item1)
    itemDao.insert(item2)
}
  1. 为向数据库中插入单个商品的 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 的原因。

  1. 运行测试并确保测试通过。

2f0ddde91781d6bd.png

8f66e03d03aac31a.png

  1. 为数据库中的 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)
}

在上述测试中,您在协程内向数据库中添加了两个商品。然后,您读取了这两个商品,并将其与预期值进行比较。

posted @ 2024-06-19 22:18  混沌武士丞  阅读(1)  评论(0编辑  收藏  举报