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

如何为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 20:10:34