You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin中Room数据库测试Mock SQLiteOpenHelper报错求助

解决Room数据库测试中SQLiteOpenHelper未Mock的问题

你在为Android平台的Kotlin版Room数据库编写测试用例时,使用如下DummyDatabase实现出现报错:

DummyDatabase.kt

internal abstract class DummyDatabase : RoomDatabase() {
    companion object {
        
        @Volatile
        private var INSTANCE: DummyDatabase? = null

        fun getInstance(context: Context): DummyDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context,
                    DummyDatabase::class.java,
                    "db_name.db"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

报错信息

Method getWritableDatabase in android.database.sqlite.SQLiteOpenHelper not mocked. See http://g.co/androidstudio/not-mocked for details.
java.lang.RuntimeException: Method getWritableDatabase in android.database.sqlite.SQLiteOpenHelper not mocked. See http://g.co/androidstudio/not-mocked for details.
    at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java)


  public void update(final ComplicationRoutine complicationRoutine) {
    __db.assertNotSuspendingTransaction();

这个错误的核心原因是:本地单元测试(运行在JVM上)使用的Android框架是桩实现(仅占位,无真实逻辑),当你调用Room.databaseBuilder()创建真实数据库时,会触发SQLite相关的未实现方法。下面提供两种解决方案,优先推荐第一种:


方案1:使用Room内存数据库进行测试(官方推荐)

这种方式使用真实的SQLite内存数据库,既能验证Room的SQL逻辑和数据持久化,又不会在设备上留下测试数据。

步骤1:添加测试依赖

在Module级别的build.gradle.kts(或build.gradle)中添加Room测试相关依赖:

testImplementation("androidx.room:room-testing:$room_version")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version")

(替换$room_version和$coroutines_version为你项目中使用的版本号)

步骤2:编写测试用例

直接在测试类中创建内存数据库,替代原有的单例获取方式:

import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import org.junit.After
import org.junit.Before
import org.junit.Test

class DummyDatabaseTest {
    private lateinit var database: DummyDatabase
    private lateinit var dummyDao: DummyDao // 假设你的数据库包含该DAO

    @Before
    fun setup() {
        // 创建内存数据库,测试结束后自动销毁
        database = Room.inMemoryDatabaseBuilder(
            ApplicationProvider.getApplicationContext(),
            DummyDatabase::class.java
        )
            // 允许主线程查询(仅测试场景下使用,生产环境禁用)
            .allowMainThreadQueries()
            .build()
        dummyDao = database.dummyDao()
    }

    @After
    fun teardown() {
        // 测试结束关闭数据库
        database.close()
    }

    @Test
    fun testUpdateComplicationRoutine() {
        // 测试逻辑示例:插入数据后更新,验证结果
        val testRoutine = ComplicationRoutine(id = 1, name = "初始名称")
        dummyDao.insert(testRoutine)

        val updatedRoutine = testRoutine.copy(name = "更新后名称")
        dummyDao.update(updatedRoutine)

        val result = dummyDao.getById(1)
        assert(result?.name == "更新后名称")
    }
}

方案2:Mock Room数据库和DAO(仅验证方法调用)

如果你只需要验证方法是否被正确调用,不需要测试SQL逻辑,可以用Mockito来Mock相关对象。注意这种方式无法验证数据持久化的正确性,仅适用于简单的逻辑验证。

步骤1:添加Mockito依赖

testImplementation("org.mockito:mockito-core:4.11.0")
testImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0")

步骤2:编写Mock测试用例

import org.junit.Before
import org.junit.Test
import org.mockito.Mockito.mock
import org.mockito.Mockito.`when`
import org.mockito.kotlin.verify

class DummyDatabaseMockTest {
    private lateinit var mockDatabase: DummyDatabase
    private lateinit var mockDao: DummyDao

    @Before
    fun setup() {
        // Mock DAO和Database对象
        mockDao = mock(DummyDao::class.java)
        mockDatabase = mock(DummyDatabase::class.java)
        
        // 配置Mock数据库返回Mock DAO
        `when`(mockDatabase.dummyDao()).thenReturn(mockDao)
        
        // 替换单例中的INSTANCE为Mock对象
        DummyDatabase.INSTANCE = mockDatabase
    }

    @Test
    fun testUpdateMethodInvocation() {
        val testRoutine = ComplicationRoutine(id = 1, name = "测试数据")
        // 调用依赖DAO的业务方法(比如Repository中的update)
        yourRepository.update(testRoutine)
        
        // 验证DAO的update方法是否被正确调用
        verify(mockDao).update(testRoutine)
    }
}

内容的提问来源于stack exchange,提问作者Yash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 15:51:02