Android Jetpack Compose如何测试背景颜色

7
我有一个可组合的东西,可以设置背景颜色,我想测试它。
@Composable
fun MyComposableButton(
    enabledColor: Color,
    disableColor: Color,
    isEnabled: Boolean = true,
) {
    val buttonBackgroundColor = if (enabled) enabledColor else disableColor
    Button(
        ...
        enabled = enabled,
        colors = ButtonDefaults.textButtonColors(
            backgroundColor = buttonBackgroundColor
        )
    ) { ... }
}

我希望写一些测试,比如:verifyEnabledBackgroundColorverifyDisabledBakcgroundColor

我找不到可以直接使用的验证语句,当我试图创建自己的验证语句时,我发现SemanticMatcther使用了SemanticNode,但是最新版本的构造函数是内部的,所以这样行不通。

我尝试模拟Color,但我不能按照这个答案所说,需要更高的API级别,这在我的项目中不可行。

我该如何测试为一个组合设置背景颜色?

5个回答

6
修改cutiko的已接受答案
基于colorspace.name验证合成颜色的有效性是不起作用的,因为返回值只是颜色空间的名称。换句话说,无论实际颜色如何,测试都会通过。
实际解决方案:
如果测试的目的是区分可组合体的实际颜色是否正确,例如在可组合体的颜色动态变化时,我们需要使用方法 .readPixels,该方法提供了"打包到Int的ARGB值"。
示例用法:
val array = IntArray(20)
composeTestRule.onNodeWithTag(TestTags.CONTENT_TEXT_FIELD_TAG).captureToImage()
            .readPixels(array, startY = 500, startX = 200, width = 5, height = 4)
array.forEach { it shouldNotBe Colors().Red.convert(ColorSpaces.Srgb).hashCode() }
array.forEach { it shouldBe Colors().Pink.convert(ColorSpaces.Srgb).hashCode() }

它似乎可以工作,你是对的,我的解决方案是错误的。我在使用readPixels时遇到了问题,你能否扩展你的回答来解释一下这些参数的原因? - cutiko

5
[更新] 请阅读其他答案:https://dev59.com/icPra4cB1Zd3GeqPdlNk#72629280 经过很多试验和错误,我找到了一种方法来实现它。有一个名为captureImage的扩展程序,它具有颜色空间。通过使用它,我们可以找到颜色名称并进行相等的断言。
然而,它存在一些限制:它是节点下面的表面,因此可能无法处理多个节点或渐变。
fun SemanticsNodeInteraction.assertBackgroundColor(expectedBackground: Color) {
    val capturedName = captureToImage().colorSpace.name
    assertEquals(expectedBackground.colorSpace.name, capturedName)
}

我创建了一个可重用的扩展,例如:

composeTestRule.setContent {
    ...
}

composeTestRule.onNodeWithText(someText).assertBackgroundColor(YourColor)

注意,这可能会起作用,因为在测试中我们确保通过我们的主题:

composeTestRule.setContent {
    OurSuperCoolTheme { //your compose }
}

1
兄弟,它没起作用:)它只返回颜色空间名称,对于所有颜色来说技术上都是相同的。用颜色测试一下吧:) 已经测试过了,不起作用。 - Pietrek
@Pietrek,谢谢你让我知道了,我会去看看的。 - cutiko
1
没问题,如果我找到解决方案,我会在这里发布答案。祝好运 :) - Pietrek

3

这不是完美的,但可以让我知道图标是否使用了正确的颜色。根据之前的答案进行。

fun SemanticsNodeInteraction.assertContainsColor(tint: Color): SemanticsNodeInteraction {
    val imageBitmap = captureToImage()
    val buffer = IntArray(imageBitmap.width * imageBitmap.height)
    imageBitmap.readPixels(buffer, 0, 0, imageBitmap.width - 1, imageBitmap.height - 1)
    val pixelColors = PixelMap(buffer, 0, 0, imageBitmap.width - 1, imageBitmap.height - 1)

    (0 until imageBitmap.width).forEach { x ->
        (0 until imageBitmap.height).forEach { y ->
            if (pixelColors[x, y] == tint) return this
        }
    }
    throw AssertionError("Assert failed: The component does not contain the color")
}

似乎遍历整个视图有点浪费。那么如果组件的颜色与背景不同,它是如何工作的呢? - cutiko
不,这只是尝试在任何点上找到可组合中的特定颜色。我用它来检测我根据某些条件更改的图标的色调。对于小的可组合部件来说,效果还不错。 - Miguel Sesma
哦!我明白了!如果任何像素匹配,那就可以了。这值得评论吗,还是我只是一无所知? - cutiko
我不太喜欢注释。我更喜欢语义化的名称,比如assertContainsColor - Miguel Sesma
苹果和橙子,但随你喜欢,这是你的答案。 - cutiko

1
也许这篇文章有点旧了,但你可以使用语义匹配器。
首先,你需要创建像这样的一个语义属性和扩展。
val ColorRes = SemanticsPropertyKey<Color>("ColorRes")
var SemanticsPropertyReceiver.colorRes by ColorRes

不要使用“ColorRes”,而是可以使用一个明确的名称来指定背景颜色,比如“CardBackgroundColor”。

然后创建一个匹配器。

fun hasBackgroundColor(expectedBackgroundColor: Color) =
    SemanticsMatcher.expectValue(ColorRes, expectedBackgroundColor)

然后像这样为可组合项添加语义修饰符

Row(
    modifier = Modifier
                .testTag("someTestTag")
                .semantics {
                    colorRes = theColorYouWant
                }
    )

最后创建测试

@Test
fun `Assert the background color`() {
//Some code to setContent ...
        composeTestRule
            .onNode(
                hasTestTag("deviceSignalContainer") and hasBackgroundColor(YourColor.Red),
                useUnmergedTree = true
            ).assertIsDisplayed()
    }

就这些了。


问题在于您必须修改组合组件代码。如果有人错过了新的约定并像标准一样使用 Modifier.background,它将无法正常工作。这会带来其他组件的特定问题,例如:SurfaceCard 会发生什么情况,这些组件必须在参数函数中使用背景颜色,不能通过 modifier 提供。不过,拥有替代方案是很好的。 - cutiko
好的,需要使用一个明确的名称,而不是"colorRes",你可以使用"backgroundColorRes"或者"SurfaceBackgroundColorRes",具体取决于需要。 - Armin

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接