Compose UI测试因Idling Resource超时失败(疑似存在无限重组)
Compose UI测试因Idling Resource超时失败(疑似存在无限重组)
嘿,我仔细看了你的测试代码和PersonCard实现,这个超时问题十有八九是无限重组循环导致的——Compose一直在重复重组,根本停不下来,所以Espresso的空闲资源检查超时了。咱们来一步步解决:
问题根源
你在PersonCard里创建了几个关键对象,但没给它们加上remember修饰,导致每次Compose重组时都会生成新的实例,进而触发新一轮重组,形成循环:
ImageRequest每次重组都会新建,导致rememberAsyncImagePainter的model参数变化placeholderPainter没有用remember包裹,每次重组都会重新创建colorFilter的计算没有依赖remember,每次重组都会重新计算,可能间接触发状态变化
修复方案
给这些易变的对象加上remember,并指定正确的依赖项,确保只有当依赖的状态真的变化时才重建:
修改后的PersonCard代码
@Composable fun PersonCard( modifier: Modifier = Modifier, person: Credit, navController: NavController? = null, ) { Column( modifier .padding(TMDb_4_dp) .clickable { navController?.navigate("${MainDestinations.TMDB_PERSON_ROUTE}/${person.id}") }, horizontalAlignment = Alignment.CenterHorizontally, ) { Card( shape = CircleShape, elevation = TMDb_8_dp, modifier = Modifier.size(TMDb_120_dp), ) { // 仅在person的profileUrl变化时重建ImageRequest val request = remember(person.profileUrl) { ImageRequest.Builder(LocalContext.current) .data(person.profileUrl) .crossfade(true) .transformations(CircleTopCropTransformation()) .build() } // 仅在person的gender变化时重建placeholderPainter val placeholderPainter = remember(person.gender) { rememberVectorPainter(person.gender.placeholderIcon) } val painter = rememberAsyncImagePainter( model = request, error = placeholderPainter, placeholder = placeholderPainter, ) // 仅在painter的状态变化时重新计算colorFilter val colorFilter = remember(painter.state) { when (painter.state) { is AsyncImagePainter.State.Error, is AsyncImagePainter.State.Loading -> ColorFilter.tint( MaterialTheme.colors.imageTint, ) else -> null } } Image( painter = painter, colorFilter = colorFilter, contentDescription = stringResource( id = R.string.person_content_description, person.name, person.role, ), contentScale = ContentScale.FillHeight, ) } Text( text = person.name, style = MaterialTheme.typography.subtitle1.copy(fontWeight = FontWeight.SemiBold), maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.padding(top = TMDb_4_dp), ) Text( text = person.role, style = MaterialTheme.typography.subtitle2.copy( fontWeight = FontWeight.Normal, fontStyle = FontStyle.Italic, ), maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.padding(top = TMDb_2_dp), ) } }
额外的测试小提示
测试里获取字符串的方式没问题,但可以考虑在setContent里直接用stringResource来生成预期的内容描述,避免依赖activity的上下文:
onNodeWithContentDescription( stringResource( R.string.person_content_description, "name", "role", ), ).assertIsDisplayed()
这样修改后,Compose就不会陷入无限重组循环了,你的测试应该就能顺利通过啦!
内容来源于stack exchange
相关产品推荐
相关产品推荐

