Tutoriais

Alternativas aos recursos de inatividade em testes do Compose: as APIs waitUntil (atualizadas)

Leitura de 3 minutos
Jose Alcérreca
Engenheira de relações com desenvolvedores

Neste artigo, você vai aprender a usar a API de teste waitUntil no Compose para aguardar o cumprimento de algumas condições. Essa é uma boa alternativa ao uso de recursos de inatividade em algumas situações.

[Atualização de 2023] Resumo: use as novas APIs waitUntil para sincronizar em testes do Compose (v1.4.0 ou mais recente).


O que é sincronização?

Uma maneira de categorizar os testes é pelo escopo. Os testes pequenos, ou de unidade, se concentram em pequenas partes do app, enquanto os testes grandes, ou completos, cobrem uma grande parte dele. Leia sobre esse e outros tipos de testes na documentação de teste atualizada.

Pressione "Enter" ou clique para ver a imagem no tamanho original

large_0_9n_Nqkt_HHUTOQ_In_AI_b113b43bcf.png
Diferentes escopos de teste em um app

A sincronização é o mecanismo que informa ao teste quando executar a próxima operação. Quanto maior o trecho de código que você escolhe verificar, mais difícil é sincronizar com o teste. Nos testes de unidade, é fácil ter controle total da execução do código para verificar. No entanto, à medida que aumentamos o escopo para incluir mais classes, módulos e camadas, fica difícil para a estrutura de teste saber se o app está no meio de uma operação ou não.

Pressione "Enter" ou clique para ver a imagem no tamanho original

large_correct_b1a355f41b.webp
Sincronização correta entre o teste e o app

O androidx.test e, por extensão, o Compose Test usam alguns truques nos bastidores para que você não precise se preocupar muito com isso. Por exemplo, se a linha de execução principal estiver ocupada, o teste será pausado até que possa executar a próxima linha.

No entanto, eles não podem saber tudo. Por exemplo, se você carregar dados em uma linha de execução em segundo plano, a estrutura de teste poderá executar a próxima operação muito cedo, fazendo com que o teste falhe. A pior situação é quando isso acontece apenas uma pequena porcentagem das vezes, tornando o teste instável.

Opção 1: recursos ociosos

Os recursos de inatividade são um recurso do Espresso que permite que você, o desenvolvedor, decida quando o app está ocupado. Há duas maneiras de usar esses dados:

1. Instalar no framework ou na biblioteca que está fazendo um trabalho que o teste não consegue ver.

Um bom exemplo disso é o RxIdler, que envolve um programador do RxJava. Essa é a maneira preferida de registrar recursos de inatividade porque permite manter a configuração de teste separada do código de teste.

2. Modificar o código em teste para expor explicitamente informações sobre se o app está ocupado ou não.

Por exemplo, você pode modificar seu repositório (ou um test double) para indicar que ele está ocupado ao carregar dados de uma fonte de dados:

Isso não é o ideal porque você está poluindo seu código de produção ou criando substitutos de teste complicados, e há algumas situações em que eles são difíceis de instalar. Por exemplo, como você usaria recursos de inatividade em um fluxo do Kotlin? Qual é a última atualização?

Em vez disso, podemos esperar as coisas.

Opção 2: esperar as coisas… do jeito errado

O carregamento de dados geralmente é rápido, especialmente quando se usam dados falsos. Então, por que perder tempo com recursos ociosos quando você pode apenas fazer o teste ficar inativo por alguns segundos?

Esse teste vai ser executado mais lentamente do que o necessário ou falhar. Quando você tem centenas ou milhares de testes de UI, quer que eles sejam o mais rápidos possível.

Além disso, às vezes, emuladores ou dispositivos têm um comportamento inadequado e instabilidade, fazendo com que essa operação leve um pouco mais de 2.000 ms, o que interrompe o build. Quando você tem centenas de testes, isso se torna um grande problema.

0_DOCdjq-JpPDGV5OB.png

Opção 3: esperar da maneira certa!

Se você não quiser modificar o código em teste para expor quando ele está ocupado, outra opção é esperar até que uma determinada condição seja atendida, em vez de esperar por um período arbitrário.

1_jIYFxE4qlHXMi2SwW6JemA.png

No Compose, você pode usar a função waitUntil, que usa outra função que produz um booleano.

Atualização de 22/03/2023: a partir do Compose 1.4.0, adicionamos um novo conjunto de APIs waitUntil:

[Antes da versão 1.4.0: use estes helpers: waitUntilExists, waitUntilNodeCount]

…e use-os assim:

Use essas APIs apenas quando precisar sincronizar seu teste com a interface. A sincronização em todas as instruções de teste polui o código de teste desnecessariamente, dificultando a manutenção.

Quando usar? Um bom caso de uso é carregar dados de um observável (com LiveData, Kotlin Flow ou RxJava). Quando a interface precisa receber várias atualizações antes de ser considerada inativa, talvez seja melhor simplificar a sincronização usando waitUntil.

Por exemplo, ao coletar um fluxo de uma visualização:

e você emite vários itens para ele:

Se repository levar um tempo indeterminado para retornar com o primeiro resultado, a estrutura de teste vai entender que "Carregando" é o estado inativo (o valor inicial atribuído em collectAsState) e continuar com a próxima instrução.

Portanto, você pode tornar o teste muito mais confiável se garantir que a interface não esteja mostrando o indicador de carregamento:


Divirta-se… aguarde… testando!


Licença de snippets de código:

  Copyright 2022 Google LLC.
SPDX-License-Identifier: Apache-2.0
Escrito por:

Continuar lendo