如何使用 Coil + Compose 来单元测试图像是否已加载

ngl*_*ber 3 android android-jetpack-compose coil android-jetpack-compose-testing

我正在使用Coil for Compose加载图像,如下所示。

@Composable
fun SvgImageSample() {
    val painter = rememberAsyncImagePainter(
        model = ImageRequest.Builder(LocalContext.current)
            .decoderFactory(SvgDecoder.Factory())
            .data("https://someserver.com/SVG_image.svg")
            .size(Size.ORIGINAL)
            .build()
    )
    Image(
        painter = painter,
        modifier = Modifier.size(100.dp).testTag("myImg"),
        contentDescription = null
    )
}
Run Code Online (Sandbox Code Playgroud)

图像已正确加载。现在,我想编写一个测试来检查图像是否已加载。有没有现成的断言

像这样的东西:

class MyTest {
    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun checkIfTheImageLoads() {
        composeTestRule.setContent {
            MyAppThemeTheme {
                SvgImageSample()
            }
        }
        composeTestRule.onNodeWithTag("myImg")
            .assertCoilImageIsLoaded() // <- this is what I want
    }
}
Run Code Online (Sandbox Code Playgroud)

ngl*_*ber 5

我找到了我正在寻找的东西...如果有人有更好的解决方案,请告诉我。

这就是我所做的:

  1. 在您的build.gradle.
implementation "androidx.test.espresso.idling:idling-concurrent:3.5.0-alpha07"
Run Code Online (Sandbox Code Playgroud)

这是使用该类所必需的IdlingThreadPoolExecutor

  1. 声明一个IdlingThreadPool对象如下:
implementation "androidx.test.espresso.idling:idling-concurrent:3.5.0-alpha07"
Run Code Online (Sandbox Code Playgroud)

我从Coil github 页面的这个问题中得到了这个提示。

  1. 在对象中使用上面声明的对象ImageRequest
object IdlingThreadPool: IdlingThreadPoolExecutor(
    "coroutinesDispatchersThreadPool",
    Runtime.getRuntime().availableProcessors(),
    Runtime.getRuntime().availableProcessors(),
    0L,
    TimeUnit.MILLISECONDS,
    LinkedBlockingQueue(),
    Executors.defaultThreadFactory()
)
Run Code Online (Sandbox Code Playgroud)

请注意该IdlingThreadPool对象已在函数中使用dispatcher。另一个细节是coilAsyncPainter接收painter对象的属性。在测试过程中需要检查图像是否已加载。

  1. 声明coilAsyncPainter语义属性。
@Composable
fun SvgImageSample() {
    val painter = rememberAsyncImagePainter(
        model = ImageRequest.Builder(LocalContext.current)
            .dispatcher(IdlingThreadPool.asCoroutineDispatcher()) // << here
            .decoderFactory(SvgDecoder.Factory())
            .data("https://someserver.com/SVG_image.svg")
            .size(Size.ORIGINAL)
            .build()
    )
    Image(
        painter = painter,
        modifier = Modifier
            .size(100.dp)
            .semantics {
                testTag = "myImg"
                coilAsyncPainter = painter
            },
        contentDescription = null
    )
}
Run Code Online (Sandbox Code Playgroud)

这是您需要在应用程序代码中执行的操作。

  1. 在测试代​​码中,声明一个新的SemanticNodeInteration.
val CoilAsyncPainter = SemanticsPropertyKey<AsyncImagePainter>("CoilAsyncPainter")
var SemanticsPropertyReceiver.coilAsyncPainter by CoilAsyncPainter
Run Code Online (Sandbox Code Playgroud)

所以在这里,基本上是从语义属性获取画家对象,然后检查当前状态是否为Success

  1. 最后,这是测试。
fun SemanticsNodeInteraction.isAsyncPainterComplete(): SemanticsNodeInteraction {
    assert(
        SemanticsMatcher("Async Image is Success") { semanticsNode ->
            val painter = semanticsNode.config.getOrElseNullable(CoilAsyncPainter) { null }
            painter?.state is AsyncImagePainter.State.Success
        }
    )
    return this;
}
Run Code Online (Sandbox Code Playgroud)