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
相关产品推荐
相关产品推荐

