Como implementar Golden Tests no Flutter
Todo mundo já deve ter escutado que “em Flutter tudo é widget” e existe até na documentação oficial um exemplo de como podemos testar nossos widgets. Testes são parte importante de desenvolvimento, como é dito por alguns, são uma documentação viva do código.
No teste de exemplo da documentação um widget com um titulo “T” e uma mensagem “M” é instanciado, depois é checado se apenas um título e uma mensagem foram renderizados como esperado. Embora esse tipo de teste também tenha sua importância, os widgets no Flutter também determinam a forma como os itens serão organizados na tela.
Como testamos isso?
No framework Flutter existe um tipo de teste chamado de golden test, abaixo o link para o artigo que me apresentou esta ferramenta.
Golden Tests
O que são?
São testes onde uma vez que o “comportamento visual” esperado de um widget seja implementado será gerada uma imagem que depois vai ser usada para comparar em testes futuros se a exibição do widget está conforme o esperado.
Como implementar?
É muito simples criar um golden test, esses são os passos:
- Criar a função de testes;
- Renderizar o widget;
- Definir o arquivo que será utilizado para o golden test.
Para gerar a imagem que será utilizada para comparação nos testes futuros deve-se rodar o seguinte comando passando o arquivo de testes de interesse:
flutter test --update-goldens test/my_widget_golden_test.dart
Abaixo é possível ver o comparativo entre o aplicativo exemplo do Flutter renderizado em um dispositivo e a imagem gerada pelo teste:
Criando uma extension para os testes
Embora esses testes sejam muito úteis, a resolução na qual eles executam não corresponde a maioria dos nossos casos de uso e seria melhor realizá-los em resoluções mais próximas do que se encontra nos dispositivos físicos. Tomando isso como objetivo vamos estender o WidgetTester para que fique mais fácil usar resoluções customizadas. No artigo abaixo é descrito como criar a extensão e também como habilitar as fontes na imagem gerada:
A extension ficaria assim:
Exemplo prático
A seguir temos um exemplo de uma lista colorida de Containers usando um Wrap para fazer com que, caso não haja espaço na tela para todos os Containers aparecerem um ao lado do outro, será feita uma “quebra de linha” para que eles continuem sendo exibidos abaixo:
Como pode ser visto na figura abaixo, a imagem gerada pelo teste não tem comportamento similar a um dispositivo fisico devido a diferença de resolução.
Atualizando nossos testes para obter imagens que correspondem melhor ao comportamento real do Widget nos casos de uso desejados:
A partir deste novo teste agora usando a extension do WidgetTester para definir tamanhos de tela foram obtidas as duas imagens abaixo que são representações muito melhores do comportamento em um dispositivo real como foi visto na figura 2.
O que acontece quando o comportamento do widget muda?
Vamos supor que, ainda usando o exemplo anterior, agora não se deseja mais que seja criada uma nova linha para os quadrados caso não haja mais espaço na tela, agora teremos uma lista onde o usuário poderá fazer a rolagem horizontal. Código modificado com este comportamento:
Agora vamos rodar o comando flutter test e observar a saída produzida:
Como já era esperado o teste falhou, como pode ser visto na figura 5. Lendo o texto que foi exibido no terminal também é possível ver que uma pasta “failures” foi criada para armazenar o feedback de falha do teste. vamos agora inspecionar o conteúdo desta pasta.
Como pode ser visto na figura 6, para cada teste que falhou foram criadas 4 imagens:
- Imagem com o comportamento anterior;
- Imagem com o comportamento atual;
- Uma imagem com as diferenças mascaradas;
- Uma imagem com as diferenças isoladas (contém apenas as diferenças, todo o resto é transparente).
Abaixo uma das imagens com as diferenças mascaradas e isoladas para que fique mais fácil de entender o que cada uma significa:
Como essa era uma mudança de comportamento. Precisamos atualizar a imagem de referencia dos nossos testes para que eles voltem a ser válidos. Isso é feito usando o comando abaixo novamente:
flutter test --update-goldens
Pronto! Agora nossos testes foram atualizados e correspondem ao comportamento esperado, já podemos submeter as nossas mudanças para o GitHub.
Automatizando seus testes usando o Github Actions
Testes podem levar um tempo considerável para executar, principalmente quando se tem muitos testes, por este motivo automatizá-los no nosso sistema de controle de versão (GitHub) é muito importante. A seguir está a configuração usada para testar esse projeto usando o Github Actions:
Com esta configuração toda vez que um novo commit é feito ou uma nova pull request é aberta para o branch master o comando flutter test será executado, e todos os testes dentro da pasta test do projeto serão executados. Ainda é possível criar uma badge de status para usar no “read me” do projeto deixando assim os resultados dos testes mais visível.
Problemas encontrados
Os golden tests dependem de uma imagem para a comparação, isso já é um problema, teremos um aumento no tamanho do repositório, são apenas alguns kbytes por imagem, mas em grande quantidade isso pode ter algum impacto, nos testes realizados as imagens com resolução 360x640 e 412x824 tiveram os tamanhos respectivos de 3KB e 4KB.
Outro problema foi encontrado ao executar os testes no Github Actions, infelizmente os resultados dos testes podem sofrer variações a depender do sistema operacional onde foi executado e por isso foi necessário usar o MacOS nos testes do Github também, este ponto impossibilita que membros do mesmo time, com sistemas operacionais diferentes sejam capazes de executar esses testes. Por este motivo recomendo que os golden tests tenham sua própria pasta, desta forma eles precisariam ser explicitamente executados nos ambientes que for conveniente.