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

如何在JUnit4中无Mock测试自定义Proto DataStore?

无Mock测试自定义Proto DataStore的实现方法

要测试自定义Proto DataStore的实际增删改操作,核心是在测试环境中创建真实的DataStore实例,使用测试协程作用域和临时文件避免污染真实数据,以下是具体实现步骤:

1. 确保Proto Serializer正确实现

首先确认你的SerializerClass符合DataStore的Serializer要求,示例实现如下:

object ListOfItemsSerializer : Serializer<ListOfItems> {
    override val defaultValue: ListOfItems = ListOfItems.getDefaultInstance()

    override suspend fun readFrom(input: InputStream): ListOfItems {
        return try {
            ListOfItems.parseFrom(input)
        } catch (e: InvalidProtocolBufferException) {
            throw CorruptionException("解析Proto数据失败", e)
        }
    }

    override suspend fun writeTo(t: ListOfItems, output: OutputStream) {
        t.writeTo(output)
    }
}

2. 单元测试:用临时文件创建DataStore

直接使用本地临时文件初始化DataStore,无需依赖Android上下文,适合快速单元测试:

class ItemRepositoryTest {
    private val testScope = TestCoroutineScope()
    private lateinit var testDataStore: DataStore<ListOfItems>
    private lateinit var tempFile: File

    @Before
    fun setup() {
        // 创建临时文件,测试后自动清理
        tempFile = File.createTempFile("test_items", ".proto")
        testDataStore = DataStoreFactory.create(
            serializer = ListOfItemsSerializer,
            scope = testScope,
            produceFile = { tempFile }
        )
    }

    @After
    fun teardown() {
        testScope.cleanupTestCoroutines()
        tempFile.delete()
    }

    @Test
    fun `添加Item后数据应持久化`() = testScope.runBlockingTest {
        // 验证初始状态
        assertEquals(0, testDataStore.data.first().itemsCount)

        // 执行添加操作
        testDataStore.updateData { currentState ->
            currentState.toBuilder()
                .addItems(
                    SomeItem.newBuilder()
                        .setItemId("1")
                        .setItemDescription("测试Item")
                        .build()
                )
                .build()
        }

        // 验证结果
        val storedItems = testDataStore.data.first().itemsList
        assertEquals(1, storedItems.size)
        assertEquals("1", storedItems[0].itemId)
        assertEquals("测试Item", storedItems[0].itemDescription)
    }
}

3. Robolectric测试:模拟真实Android上下文

如果需要更贴近真实应用环境的测试,可使用Robolectric提供的Android上下文,在应用文件目录下创建临时DataStore文件:

@RunWith(RobolectricTestRunner::class)
class ItemRepositoryRobolectricTest {
    private val testScope = TestCoroutineScope()
    private lateinit var testDataStore: DataStore<ListOfItems>
    private val testContext = ApplicationProvider.getApplicationContext<Context>()

    @Before
    fun setup() {
        val testFile = File(testContext.filesDir, "test_items_store.proto")
        // 每次测试前清空旧文件
        testFile.delete()

        testDataStore = DataStoreFactory.create(
            serializer = ListOfItemsSerializer,
            scope = testScope,
            produceFile = { testFile }
        )
    }

    @After
    fun teardown() {
        testScope.cleanupTestCoroutines()
        File(testContext.filesDir, "test_items_store.proto").delete()
    }

    @Test
    fun `删除Item后数据应更新`() = testScope.runBlockingTest {
        // 先添加测试数据
        testDataStore.updateData {
            it.toBuilder()
                .addItems(SomeItem.newBuilder().setItemId("1").build())
                .build()
        }
        assertEquals(1, testDataStore.data.first().itemsCount)

        // 执行删除操作
        testDataStore.updateData { currentState ->
            currentState.toBuilder()
                .removeItems(0)
                .build()
        }

        // 验证结果
        assertEquals(0, testDataStore.data.first().itemsCount)
    }
}

常见问题说明

你之前通过ApplicationProvider.getApplicationContext()获取的上下文没有DataStore引用,是因为应用中的Context.someItemsStore是自定义扩展属性,测试环境未导入或初始化该扩展。直接手动创建DataStore实例是更独立、可控的测试方式,无需依赖应用的扩展属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 12:05:36