6 características fundamentais de um teste bem escrito – Robson Castilho
Testes automatizados não são mais novidade hoje em dia. Um grande número de empresas e desenvolvedores escrevem testes como algo trivial do trabalho, o que é bastante positivo.
No entanto, com um número cada vez mais elevado de testes em um software, é fundamental que tenhamos o mesmo cuidado com a suíte de testes que temos com o código de produção, caso contrário, podemos terminar com centenas ou milhares de testes de difícil manutenção, minando a produtividade do time e elevando os custos de manutenção.
Abaixo seguem 6 características fundamentais para a escrita de testes com qualidade:
1. 100% AUTOMATIZADO
Um teste não pode ser "pseudo-automatizado". Se antes ou depois de um teste rodar, você tenha que manualmente inserir um registro no banco de dados, excluir um arquivo da sua máquina, subir um servidor, pedir para o Pepe tirar a vela (*), etc…, você está fazendo algo muito errado!
Não seja "gambiarreiro": automatize o teste do começo ao fim.
Considere o uso de fakes, caso um recurso externo não-confiável precise ser chamado.
Favoreça testes de unidade aos integrados (considere a Pirâmide de Testes).
(*) se você nunca assistiu Chapolin, está fazendo 2 coisas muito errado!
Todo teste, e, em especial, a suíte toda de testes, deve ser rápida o bastante para que você possa rodá-la com frequência. O quão rápido é algo relativo, mas, no mínimo os testes de unidade (todos eles, sejam centenas ou milhares) devem rodar em questão de segundos ou menos. A suíte toda não deve travar seu deploy por horas.
Verifique o desempenho de testes integrados e considere o uso de fakes, caso um recurso externo muito lento esteja sendo chamado.
Remova testes duplicados, aqueles que cobrem o mesmo código, no mesmo cenário.
Mantenha o teste simples (complexidade ciclomática de 1).
3. DETERMINÍSTICO
Assumindo que nada foi alterado no código de produção e no próprio teste, dada a mesma entrada, o teste deve produzir a mesma saída. Sempre! Independente do dia, do seu humor, da sua sorte e das condições climáticas.
Utilize test doubles para forçar previsibilidade no teste. Isto é, código que trabalha com data/hora atual, números gerados aleatoriamente e dependências externas pode ser refatorado para depender de abstrações (e um test double usado no teste no lugar da dependência real).
Todo teste deve ser autossuficiente, isto é, não deve depender da execução de algum outro teste.
Não seja "gambiarreiro". Nada de setar uma variável em um teste para usá-la em outro ou qualquer coisa bizarra do tipo.
5. LEGÍVEL
Em um código de teste, deve-se entender, facilmente, o que está sendo testado, com quais entradas e quais as saídas esperadas (o que significa que ele precisa ser o mais simples e descritivo possível).
Utilize técnicas como estas: Deixando seus testes mais robustos e legíveis.
Por fim, um teste que quebra/falha por alterações em código de produção que não tenham nenhuma relação com aquele teste é considerado um teste frágil. Isso acontece quando um teste está muito acoplado ao código de produção (do próprio objeto testado ou de outros), mais comum de se ver na fase de setup do teste.
Um teste também pode ser frágil caso ele conheça demais detalhes de implementação do objeto testado, isto é, quando se "mocka" praticamente todo o comportamento do método sob teste.
Isole o teste o máximo possível do código de produção usando helpers de teste: Deixando seus testes mais robustos e legíveis.
Não saia "mockando" tudo: Mockar demais é perigoso.
Com uma suíte de testes onde a maioria deles (se possível, todos) atenda essas 6 características, é bastante provável que os testes estejam saudáveis e que você e seu time estejam realmente sendo beneficiados por eles, ao invés de estarem sendo atrapalhados.
Uma última dica, não menos importante, é que devemos cuidar dos testes o tempo todo, eliminando testes redundantes e praticando refactoring ao sinal de qualquer smell (um bom livro de referência para isso é o XUnit Test Patterns).