
Um teste flaky passa e falha no mesmo código. Nada mudou entre as duas execuções a não ser os tempos, a ordem, ou algo fora do teste em que ninguém estava a pensar.
É pior do que um teste que falha sempre, e não é uma forma de dizer. Um teste que falha sempre fica resolvido antes do almoço. Um teste que falha uma vez em cada dez ensina uma equipa inteira a carregar no botão de repetir, e assim que esse hábito existe, cada falha genuína tem de disputar com o ruído a atenção de alguém.
O que custa a instabilidade
Treina as pessoas a ignorar o vermelho. Da primeira vez que uma build falha, alguém vai ver. Ao vigésimo falso alarme, a resposta é repetir e encolher os ombros, e uma regressão a sério recebe o mesmo encolher de ombros.
Esconde-se no meio da multidão. Uma suite com uma dúzia de testes pouco fiáveis falha vezes suficientes para que ninguém consiga distinguir uma falha pouco fiável de uma verdadeira sem a abrir, portanto ninguém a abre.
Torna a suite mais lenta e menos fiável ao mesmo tempo. Cada repetição custa minutos; a dúvida custa mais.
De onde vem a instabilidade
Quase toda ela é uma de cinco coisas.
Esperar pela coisa errada. De longe o caso mais comum nos testes de browser. O teste pergunta se algo está visível enquanto ainda está a aparecer, ou verifica um estado a que a interface chega uma fração de segundo depois. Passa numa máquina rápida e falha num servidor de build carregado, que é precisamente a máquina onde não se pode depurar.
Dependência da ordem. Um teste que só passa depois de outro ter corrido, porque esse criou o registo, definiu o estado ou deixou alguma coisa para trás. Corra a suite noutra ordem, ou em paralelo, e ela desfaz-se.
Estado partilhado. Uma linha de base de dados, um valor em cache, um ficheiro em disco, um relógio. Dois testes que usam a mesma fixture acabarão por correr suficientemente perto um do outro para interferirem.
O tempo. Tudo o que verifica a data de hoje acaba por atravessar a meia-noite; tudo o que tem um tempo limite falha sob carga; tudo o que depende da ordem de dois eventos sem garantia de ordenação é uma moeda ao ar que ainda não reparou.
O mundo lá fora. Um teste que chega a uma rede real, a um serviço de terceiros real ou a um relógio real pediu emprestada a disponibilidade de outra pessoa.
O erro que esconde a maior parte deles
O fio comum aos casos de temporização merece ser dito à parte, porque muda a forma como se escreve a verificação.
- Esperar por uma transição
- Verificar que o botão mostra a sua etiqueta em repouso, enquanto a animação que limpa o estado anterior ainda está a correr
- Esperar por um estado
- Verificar que a classe "copied" desapareceu, e só então que a etiqueta em repouso está lá
O primeiro é uma corrida entre a paciência da framework de testes e o temporizador da interface. Passa numa máquina sossegada e falha numa ocupada, e a mensagem de erro é confusa em vez de informativa: o elemento está presente, com o texto certo, e simplesmente ainda não está visível.
Esse exemplo é real: é um teste desta mesma base de código, e falhou exatamente uma vez, num runner carregado, num commit que mudava dois ficheiros de imagem.
O que fazer com um
Não o resolva esperando mais tempo. Subir um tempo limite global torna mais lento o caminho de falha de todos os outros testes e esconde a corrida seguinte em vez de a remover. É o equivalente a subir o volume da música.
Também não o apague, pelo menos não em primeiro lugar. Um teste flaky costuma estar a apontar para algo real: uma corrida genuína no produto, uma interface que anuncia que terminou antes de ter terminado, um recurso partilhado que duas coisas usam. Corrigir o teste às vezes significa corrigir a aplicação.
Quarentena, depois correção, com prazo. Tire-o da suite bloqueante para que deixe de ensinar as pessoas a ignorar o vermelho, e ponha-lhe uma data. Quarentena sem prazo é apagar com passos a mais e a consciência mais pesada.
Conte-os. Uma equipa que não sabe dizer quantos testes flaky tem vai descobrir quando o número for grande. Se o seu runner regista as repetições, esse é o número a vigiar.
Quando a instabilidade é culpa do produto
Às vezes o teste tem razão e o software é que não é fiável: um pedido que de vez em quando chega fora de ordem, uma interface que diz “guardado” antes de a gravação estar completa, um trabalho que normalmente termina antes de a página recarregar.
Esses são defeitos a sério e são penosos de comunicar, porque por definição não acontecem todas as vezes. O que os torna reproduzíveis para outra pessoa é o contexto da execução que falhou, e não a descrição das dez que passaram.
Session Replay
Extensão gratuita do Chrome. Um clique na página que se está a portar mal captura a captura de ecrã, a consola e o registo de rede, e devolve-lhe um link para colar no ticket.
Para um defeito intermitente, diga com que frequência acontece e o que estava a fazer quando aconteceu: “três vezes em cerca de vinte tentativas, sempre logo a seguir a guardar” é bem mais útil do que a descrição de uma única ocorrência. O guia do relatório de erro trata do resto.
A versão curta
Um teste flaky falha em código que não mudou, e o seu custo verdadeiro é ensinar as pessoas a ignorar falhas. A maior parte são um teste à espera de uma transição em vez de um estado, uma dependência da ordem, ou estado partilhado. Corrija a causa em vez do tempo limite, ponha em quarentena com prazo em vez de indefinidamente, e leve a sério a possibilidade de o teste ter razão e de o software ser aquilo que não é fiável.