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

如何让Compose截图测试读取screenshotTest上下文外的跨模块Assets

Compose Preview Screenshot Testing跨模块资源访问问题

项目结构

  • :app模块:仅负责启动功能界面
  • :feature:chat模块:包含完整功能代码、Composable组件及对应预览,截图测试代码路径为feature\chat\src\screenshotTest\...\PreviewScreenshotCode.kt
  • :core模块:存放预览富内容所需的json、text文件,通过context.resources.assets.open(...)读取

问题现象

正常Compose预览可正常读取:core模块的Assets资源并渲染UI,但截图测试时无法访问该模块Assets资源,推测是screenshotTest上下文与:core模块Assets环境差异导致,尝试修改上下文未解决。


方案A:让截图库访问其他模块的Assets资源

截图测试默认使用当前测试模块(:feature:chat)的上下文,无法直接跨模块读取Assets,可通过两种方式解决:

  1. 复制:core模块Assets到测试模块
    在:feature:chat模块的build.gradle.kts中添加Gradle任务,将:core模块的Assets复制到当前模块的screenshotTest资源目录:

    tasks.register<Copy>("copyCoreAssetsToScreenshotTest") {
        from(project(":core").file("src/main/assets"))
        into("src/screenshotTest/assets")
        dependsOn(":core:assemble")
    }
    
    // 让截图测试任务依赖该复制任务
    tasks.withType<Test>().configureEach {
        dependsOn("copyCoreAssetsToScreenshotTest")
    }
    

    执行任务后,截图测试上下文即可通过原有代码读取资源。

  2. 使用全局Instrumentation上下文
    替换原有上下文为InstrumentationRegistry提供的全局上下文,该上下文可访问所有模块合并后的Assets:

    val context = InstrumentationRegistry.getInstrumentation().targetContext
    val inputStream = context.resources.assets.open("sample.json")
    

    需确保:core模块的build.gradle中正确配置了Assets目录:

    android {
        sourceSets {
            main {
                assets.srcDirs("src/main/assets")
            }
        }
    }
    

方案B:自动生成包含资源内容的Kotlin Object

针对大量json/text文件,可通过Gradle任务自动生成包含资源内容的代码,无需上下文访问:

  1. 添加Gradle生成任务
    在:core模块的build.gradle.kts中注册自定义任务:

    tasks.register<JavaExec>("generateAssetObjects") {
        mainClass.set("com.yourcorepackage.AssetCodeGenerator")
        classpath = sourceSets.main.runtimeClasspath
        args = listOf(
            projectDir.resolve("src/main/assets").absolutePath,
            projectDir.resolve("src/main/java/com/yourcorepackage/generated").absolutePath
        )
    }
    
    // 让编译任务依赖生成任务
    tasks.compileKotlin.dependsOn("generateAssetObjects")
    
  2. 编写资源生成工具类
    创建AssetCodeGenerator.kt,遍历Assets目录读取文件内容并生成Kotlin Object:

    package com.yourcorepackage
    
    import java.io.File
    
    fun main(args: Array<String>) {
        val assetsDir = File(args[0])
        val outputDir = File(args[1])
        outputDir.mkdirs()
    
        val code = buildString {
            append("package com.yourcorepackage.generated\n\n")
            append("object AssetContents {\n")
            // 遍历所有json/text文件
            assetsDir.walk().filter { it.isFile && it.extension in listOf("json", "text") }.forEach { file ->
                val propertyName = file.nameWithoutExtension.replace("-", "_").replace(".", "_")
                val escapedContent = file.readText()
                    .replace("\\", "\\\\")
                    .replace("\"", "\\\"")
                    .replace("\n", "\\n")
                    .replace("\r", "\\r")
                append("    const val $propertyName = \"$escapedContent\"\n")
            }
            append("}\n")
        }
    
        File(outputDir, "AssetContents.kt").writeText(code)
    }
    
  3. 使用生成的代码
    执行generateAssetObjects任务后,直接通过AssetContents.sample_json(对应sample.json)访问资源内容,无需上下文:

    val sampleData = AssetContents.sample_json
    

    注意:大体积资源不建议用此方案,会增加代码包体积;需确保文件名转义为合法的Kotlin变量名。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 14:17:12