我有一个设置背景颜色的可组合项,我想测试一下。
@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
)
) { ... }
}
我期望编写如下测试:
verifyEnabledBackgroundColor
和verifyDisabledBakcgroundColor
。
我在撰写测试中找不到任何直接可用的断言,当尝试创建自己的断言时,我发现
SemanticMatcther
使用 SemanticNode
,但构造函数是最新的内部断言,因此无法进行。
我尝试
mock
Color
但我做不到,根据这个答案需要高API级别,这对我的项目来说是不行的。
如何测试设置可组合项的背景颜色?
纠正cutiko已接受的答案:
基于 colorspace.name 验证可组合项的颜色不起作用,因为返回的值只是颜色空间的名称。换句话说,无论实际颜色如何,测试都会通过。
实际解决方案:
如果测试的目的是区分可组合项的实际颜色是否正确,例如在可组合项的颜色动态变化的情况下,我们需要使用方法 .readPixels 提供“打包到 Int.h 中的 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() }
[更新]请阅读其他答案https://stackoverflow.com/a/72629280/4017501
经过多次尝试和错误,我找到了一种方法。有一个具有颜色空间的扩展
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 }
}
并不完美,但可以让我知道图标是否涂有正确的颜色。基于之前的答案。
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")
}
也许是旧帖子,但您可以使用语义匹配器。
首先,您需要创建一个语义属性和一个像这样的扩展
val ColorRes = SemanticsPropertyKey<Color>("ColorRes")
var SemanticsPropertyReceiver.colorRes by ColorRes
您可以使用显式名称来指定背景颜色,例如“CardBackgroundColor”,而不是使用“ColorRes”。
然后创建一个匹配器
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()
}
仅此而已。
基于: https://stackoverflow.com/a/70682865/19411871 和 https://stackoverflow.com/a/72629280/19411871
我这样做了:
fun SemanticsNodeInteraction.assertBackgroundColor(expectedBackground: Color) {
val array = IntArray(20)
captureToImage()
.readPixels(
array,
startY = 100,
startX = 200,
width = 5,
height = 4
)
array.forEach {
Assert.assertEquals(expectedBackground.convert(ColorSpaces.Srgb).hashCode(), it)
}
查看示例,该示例显示了如何通过断言应用程序栏的颜色来测试应用程序主题模式更改。您可以遵循相同的方法:
@Test
fun changeThemeMode() {
val initialThemModeColor = composeRule.onNodeWithTag(TestTags.APP_BAR).captureToImage().toPixelMap()[0, 0]
composeRule.onNodeWithTag(TestTags.THEME_MODE_BTN).performClick()
val changedThemModeColor = composeRule.onNodeWithTag(TestTags.APP_BAR).captureToImage().toPixelMap()[0, 0]
assertNotEquals(initialThemModeColor, changedThemModeColor)
}