Quantas vezes você já ouviu que testes de GUI (ou testes end to end) são flaky, frágeis, ou não confiáveis?

geek-and-poke

Pois é, há algum tempo estou realizando pesquisas à fim de escrever este post e hoje lhe trago algumas de minhas descobertas e também algumas dicas sobre tais flaky tests.

Porém, antes de começar trago uma sentença retirada do livro Entrega Contínua, de Jez Humble e David Farley, a qual considero conveniente:

“Ao seguir boas práticas e utilizar as ferramentas apropriadas, é possível reduzir drasticamente o custo da criação e manutenção de testes automatizados de aceitação ao ponto que os benefícios claramente excedem os custos.”

Ok, agora podemos começar.

Conforme um artigo publicado no Google Testing Blog, até mesmo o Google sofre com testes flaky, seja por questões relacionadas a concorrência, por depender de comportamentos não definidos ou não determinísticos, por código frágil de terceiros, problemas de infra-estrutura, entre outros.

Porém, algumas dicas interessantes deste mesmo artigo sugerem: ao encontrar testes flaky, coloque-os em quarentena para posterior investigação a fim de torná-los mais robustos e confiáveis; re-execute somente os testes que falharam para determinar se tais testes são mesmo flaky.

Apesar de esta não ser uma solução perfeita, ao menos ajuda a diminuir o tempo de investigação dos testes que podem estar falhando como falsos negativos, garantindo um feedback rápido após a execução dos testes.

Outro artigo relacionado, também do Google Testing Blog, demonstra questões relacionadas a testes de GUI na teoria versus prática, do qual discordo em algumas questões, as quais irei explicar em breve.

Neste, sugere-se que, em teoria, testes end to end são bons para: os desenvolvedores, pois a tarefa de escrevê-los fica a cargo de outros (normalmente dos testadores); os gerentes e tomadores de decisão, pois testes que simulam cenários reais dos usuários ajudam a determinar o impacto à estes em caso de falha; e para os testadores, pois estes se preocupam em não deixar bugs passarem, além de se preocuparem em escrever testes que verificam um comportamento do “mundo real”.

Neste mesmo artigo, a visão prática sobre testes end to end é que me faz não concordar com alguns pontos, visto que tentam demonstrar as fragilidades de tais testes em um cenário onde outras abordagens poderiam ser tomadas a fim de melhor mitigar os problemas.

No exemplo citado no artigo, inicialmente os testes falham devido a uma falha real na aplicação, onde o sign in não está funcionando, e visto que a grande maioria dos cenários de testes dependem do sign in, esta grande maioria falha. Aqui o ponto é, crie testes independentes o quanto for possível.

Neste caso, uma melhor abordagem, na minha opinião, seria um estágio anterior no pipeline onde somente um smoke test de testes de GUI seria executado, e neste estaria o teste de sign in, porém, o feedback de tal suite de testes seria muito mais rápida e não comprometeria todo o restante ou a grande maioria dos testes. Além disso, havia realmente uma falha na aplicação, o sign in não estava funcionando.

Outro ponto do qual discordo quando “falam mal” dos testes end to end é demonstrado quando testes flaky são identificados somente na última bateria de testes, ou seja, até então realmente existiam problemas, sejam na aplicação, em uma aplicação de terceiros a qual a aplicação principal dependia, ou na infra-estrutura onde tal aplicação estava hospedada, ou seja, tais testes não estavam falhando à toa, ou ao menos não eram somente eles os culpados pelas falhas.

Porém alguns pontos interessantes a considerar são: encontrar a causa raiz de um teste end to end falhando não é tão simples; um teste falhando não beneficia o usuário final, até que o bug seja corrigido; e, testes end to end são lentos, quando comparados à testes de unidade, ou testes de integração.

Portanto, neste segundo artigo sugere-se seguir a tão falada pirâmide dos testes, sugestão a qual concordo plenamente, como forma de “fugir” dos testes flaky, visto que testes de unidade e de integração, além de proverem um feedback mais rápido após mudanças na aplicação, também facilitam em encontrar os problemas, uma vez que tais testes exercitam um escopo menor da aplicação quando comparados com testes end to end, os quais exercitam a aplicação como um todo.

Porém, existem maneiras para criar testes end to end mais rápidos e robustos, tais como a execução de testes em paralelo e a utilização de boas práticas de desenvolvimento de testes. Só não podemos nos enganar e achar que não haverão testes frágeis, cabe a nós identificá-los e trabalhar para melhorá-los.

Já neste artigo, chamado Front-End Testing Done Right, gostaria de levantar alguns pontos interessantes:

Primeiro: Muitos programadores não consideram a criação de testes automatizados como de sua responsabilidade. Neste contexto, sempre lembro de uma frase de Klaus Wuestefeld, na qual ele diz que: “Testar software manualmente, no século 21, é antiético, é como um cirurgião operar sem lavar as mãos.” Ou seja, é responsabilidade ética do desenvolvedor criar testes automatizados.

Segundo: Se escrever testes automatizados parece difícil para os desenvolvedores algo está errado, ou eles não sabem como utilizar o framework de testes, ou este está escrito de forma incorreta. Aqui a mensagem é: “Todos temos que aprender. O tempo todo. É assim que é.”

Terceiro: “Um teste não confiável não é um teste.” E neste caso o melhor a fazer é deletá-lo (vale lembrar a possibilidade de colocá-lo em quarentena para torná-lo robusto).

Quarto: Conforme já comentado, considere a execução de testes em paralelo para diminuir o tempo de feedback da execução dos teste.

Quinto: identifique testes não determinísticos e encontre maneiras de testá-los de forma confiável, tal como: caso um teste dependa de determinados dados na aplicação para que seja executado, garanta que rotinas de escrita no banco de dados, por exemplo, sejam executadas, assim, tais dados estarão lá quando os testes forem executados. Ou então utilize alguma outra forma de injeção de dados na aplicação, mas faça isso.

Sexto: Aguarde pelo correto estado da aplicação em vez de colocar sleeps em seus testes. Utilize waits, ou seja, use validações de que tais elementos estão realmente disponíveis antes de tentar interagir com eles ou fazer verificações (ex.: aguarde por um elemento estar visível antes de interagir com o mesmo.)

Sétimo: Identifique elementos por propriedades especificamente criadas para testes, tais como data-test, ou data-test-id. Tais propriedades garantem que os testes irão interagir com os elementos corretos, portanto, sempre que uma propriedade como esta estiver disponível, não hesite em utilizá-la. Além disso, utilize Page Objects quando fizer sentido e utilize mecanismos programáticos para a criação de estado na aplicação para tonar seus testes independentes e otimizados. Tais mecanismos ajudam a respeitar o princípio DRY (Don’t repeat yourself), além de garantirem a facilidade de manutenção dos testes.

Oitavo: Não teste tudo através da GUI. Conforme já comentado a respeito da pirâmide dos testes, identifique qual a melhor camada para testar diferentes funcionalidades da aplicação, às vezes um teste de unidade já é o suficiente para testar determinada funcionalidade e evita a criação de testes flaky.

Nono: Testes devem poder ser executados independente de ambiente. Procure escrever testes que possam ser executados em ambiente local de desenvolvimento, ambiente de QA e até mesmo em ambiente de produção, se possível. Isso diminui a incidência de testes flaky em um ambiente e confiáveis em outro.

Por fim, deixo uma mensagem final misturada com a mensagem final deste outro artigo, chamado Why System tests can’t replace Unit tests. Teste end to end e testes de unidade não existem pela mesma razão, apesar de ambos existirem para prover feedback rápido após mudanças na aplicação. Estes na verdade complementam uns aos outros, portanto, se preocupe em escrevem ambos, e na medida certa. Enquanto testes de unidade lhe ajudarão com feedback em segundos e fácil debug quando problemas forem encontrados, testes de GUI reduzirão drasticamente o tempo e a necessidade da execução de testes manuais, os quais estão sujeitos ao erro humano.

Como leituras complementares sugiro os seguintes posts:

The Forgotten Layer of the Test Automation Pyramid

Introducing the Software Testing Cupcake (Anti-Pattern)

Se você gostou deste post, compartilhe, curta, ou deixa um comentário!

Até a próxima! E bons testes!!

4 comentários em “Seriam os testes de GUI flaky por natureza?

  1. Excelente artigo, parabéns.

    Realmente o que mais me incomoda e toma tempo são testes frágeis.
    Nos projeto que atuo estamos aproveitando uma mudança arquitetural dos sistemas (backend rest + angular em substituição do JSF) e priorizando testes abaixo da interface. Com isto a pirâmide fica melhor representada, já que atacamos assim um meio termo entre testes unitários e end-to-end na interface.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s