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

Jetpack Compose测试报错:如何断言按钮应用MaterialTheme.colors.primary?

解决Compose测试中“@Composable invocations can only happen from @Composables”错误

错误原因

测试代码不属于@Composable上下文,直接调用MaterialTheme.colors.primary会触发该错误——MaterialTheme的颜色属性仅能在Composable函数内部访问。

正确解决方案

方案1:在Composable上下文内获取颜色并执行断言

将颜色获取逻辑放在setContent块中(测试的Composable上下文),再传递给断言函数:

composeTestRule.setContent {
    // 在Composable上下文内获取主题颜色
    val primaryColor = MaterialTheme.colors.primary
    // 渲染测试目标组件
    Btn(shopState = 1)
    
    // 执行断言
    composeTestRule.onNodeWithText("Calculate").assertButtonColor(primaryColor)
}

方案2:优化断言函数的颜色校验逻辑

原断言仅比较颜色空间名称,无法准确验证颜色值。修改断言函数,直接校验像素颜色:

fun SemanticsNodeInteraction.assertButtonColor(expectedColor: Color) {
    val capturedImage = captureToImage()
    // 取按钮文本区域的中心像素(可根据实际布局调整取点逻辑)
    val centerX = capturedImage.width / 2
    val centerY = capturedImage.height / 2
    val pixelValue = capturedImage.getPixel(centerX, centerY)
    val actualColor = Color(pixelValue)
    
    // 考虑浮点精度误差,使用delta值比较
    assertEquals(expectedColor.red, actualColor.red, 0.01f)
    assertEquals(expectedColor.green, actualColor.green, 0.01f)
    assertEquals(expectedColor.blue, actualColor.blue, 0.01f)
    assertEquals(expectedColor.alpha, actualColor.alpha, 0.01f)
}

方案3:通过语义属性传递颜色(高效无截图)

给组件添加自定义语义属性存储颜色,测试时直接读取语义属性,无需截图:

  1. 修改Btn组件,添加语义属性:
@Composable
fun Btn(shopState: Int) {
    var color = MaterialTheme.colors.primary
    if (shopState == 2) {
        color = MaterialTheme.colors.error
    } else if (shopState == 3) {
        color = MaterialTheme.colors.secondary
    }
    Button(onClick = {}) {
        Text(
            text = "Calculate",
            color = color,
            modifier = Modifier.semantics {
                // 存储文本颜色到语义属性
                this["buttonTextColor"] = color
            }
        )
    }
}
  1. 编写对应的断言函数:
fun SemanticsNodeInteraction.assertButtonColor(expectedColor: Color) {
    val semanticsNode = fetchSemanticsNode()
    val actualColor = semanticsNode.config.getOrElse("buttonTextColor") {
        fail("未找到按钮文本颜色的语义属性")
    } as Color
    assertEquals(expectedColor, actualColor)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 08:50:39