如何为PreferencesDataStore编写Android单元测试(非Instrumentation测试)
Android DataStore 本地单元测试方案(非Instrumentation测试)
核心思路
本地单元测试无需依赖Android系统环境,因此我们使用内存版DataStore替代真实文件存储的DataStore,同时自定义Mock Context避免依赖Android框架提供的Context实例。
测试实现步骤
1. 确保测试依赖完备
在模块级build.gradle中添加本地测试所需的协程和DataStore核心依赖:
dependencies { testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3" testImplementation "androidx.datastore:datastore-preferences-core:1.0.0" }
2. 编写单元测试类
import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.intPreferencesKey import androidx.datastore.preferences.createDataStore import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import android.content.Context import java.io.File // 补充原代码中未定义的常量类 object Constants { const val PREFERENCES_NAME = "app_preferences" const val ANDROID_INDEX_VERSION = "android_index_version" val XyzKey = intPreferencesKey("xyz_key") } class DataStoreManagerTest { private lateinit var dataStore: DataStore<Preferences> private lateinit var dataStoreManager: DataStoreManager @Before fun setUp() { // 创建绑定临时文件的DataStore,测试后自动清理 dataStore = createDataStore( name = Constants.PREFERENCES_NAME, produceFile = { File.createTempFile("test_datastore", null) } ) // 自定义Mock Context,仅提供测试用的DataStore实例 val testContext = object : Context() { override val dataStore: DataStore<Preferences> get() = this@DataStoreManagerTest.dataStore // 实现Context必要的抽象方法,测试未用到的方法做最小化实现 override fun getApplicationContext(): Context = this override fun getString(resId: Int): String = throw UnsupportedOperationException() override fun getSystemService(name: String): Any? = null } // 初始化待测试的DataStoreManager dataStoreManager = DataStoreManager(testContext) } @Test fun `设置XyzKey后能正确读取对应值`() = runTest { val testMode = 5 dataStoreManager.setXyzKey(testMode) val storedValue = dataStoreManager.getXyzKey.first() assertEquals(testMode, storedValue) } @Test fun `未设置XyzKey时返回默认值-1`() = runTest { val defaultValue = dataStoreManager.getXyzKey.first() assertEquals(-1, defaultValue) } @Test fun `多次设置XyzKey后最终值正确`() = runTest { dataStoreManager.setXyzKey(10) dataStoreManager.setXyzKey(20) val finalValue = dataStoreManager.getXyzKey.first() assertEquals(20, finalValue) } }
关键细节说明
- 内存DataStore:通过
createDataStore指定临时文件,避免测试间的状态污染,测试结束后临时文件会自动删除。 - Mock Context:仅实现测试必需的
dataStore属性,其他Context方法做最小化实现,避免依赖Android系统服务。 - 协程测试:使用
runTest管理测试协程,自动处理异步逻辑的时序问题,简化测试代码。 - Flow验证:调用
first()获取Flow的首个发射值,同步完成结果验证。
注意事项
- 测试类需放在
src/test/java目录下,确保是本地单元测试而非Instrumentation测试。 - 若使用Hilt注入,可在测试组件中替换Context为自定义的Mock Context,实现依赖注入的测试隔离。
- 如需每次测试都重置DataStore状态,可在
setUp方法中添加dataStore.edit { it.clear() }。
内容的提问来源于stack exchange,提问作者Sumit Sharma
相关产品推荐
相关产品推荐

