Good test vs. bad test, como identificar?

Pedro Matias de Araujo
devorando
Published in
6 min readApr 20, 2020

Todo mundo conhece a clássica estratégia de good cop/bad cop, certo? É aquela lá, vista várias vezes em filmes, que uma dupla se divide e enquanto um encarna o bad cop que te maltrata, te faz sofrer e algumas vezes até te tortura, o outro, o good cop vai te proteger, te ajudar, para que você dê à ele as informações que estão buscando.

Aqui a analogia com testes é direta, enquanto um mal teste vai te torturar, te incomodar, te dar dor de cabeça e fazer você perder noites de sono, literalmente, um bom teste é todo o conforto que você precisa. E você vai ficar feliz com a proteção que ele vai te dar.

Mas como identificar se um teste é bom ou mau? Nesse artigo, vou te falar sobre experiências pessoais e como trabalhamos aqui no aiqfome. (Sim, usamos testes automatizados por aqui).

Todo mundo já viu essa imagem, né?

No mundo real, a questão da velocidade e o custo dos testes é uma variável que não pode ser descartada. Aqui no aiqfome, por exemplo, só usamos os testes de serviços. Por que? Alguns motivos:

  1. Mudamos muito nosso código. Estamos focados em agilidade, nossas mudanças e tomadas de decisões são rápidas. Pra acompanhar, os testes unitários teriam que sofrer tantas mudanças, pois ao refatorar o código teriam que ser alterados os testes também, que perderíamos nossa velocidade.
  2. Não nos prendemos em nenhuma linguagem ou tecnologia. Temos módulos em Python, NodeJs, PHP, Go,(algumas vezes com frameworks diferentes) e estamos sempre em busca de novas linguagens.
  3. A interface não fica de fora das mudanças. Os testes de UI também ficariam inviáveis pela quantidade de alterações diárias que realizamos.

O caminho de testes que encontramos, foi o de serviço. O meio termo onde não importa a linguagem, o que importa é que em dadas condições, o retorno na request tem que ser o mesmo. Focando os testes na lógica do negócio, damos liberdade para os devs escolherem a linguagem que quiserem em cada módulo que forem criar e, além disso, refatorar um módulo inteiro, até em outra linguagem, se for necessário.

Muitos dizem que escrever testes é uma arte: você não pode fazer muitas validações para não deixar seu teste custoso e “amarrado”, mas também não pode fazer asserts de menos, porque não vai estar testando tudo que tem que ser testado. As dicas aqui buscam o equilíbrio, como tudo na vida deve ser.

Não esqueça de testar as coisas importantes

Imagine um teste em python, que faz a request para uma aplicação e você só validou que retorne código de sucesso (200). O que aconteceria se alguém lesse seu teste? Várias perguntas surgiriam, como:

Vai vim um JSON? Qual a estrutura? Quais os campos? Tipos dos campos? Quais os seus valores? O que salvou no banco? Na cache?

Tenha sempre isso em mente. Pense que os testes também tem que ser lidos como código e busque fazer o assert em todos os pontos necessários, para mostrar que essa requisição foi realmente processada com sucesso e que não foi só um falso positivo.

Tenha sempre um teste happy day, mas não esqueça dos seus erros

Testar só os casos que funcionam é bom para saber que realmente funciona e só. Isso não agrega tanto valor e o que precisa ter mais atenção são os erros e exceções que podem acontecer (e acontecem) na sua aplicação. Confia em mim, são esses que vão te dar dor de cabeça.

Lembrando sempre, TODO MUNDO ESPERA QUE TUDO FUNCIONE EM TODAS AS CONDIÇÕES. Não adianta o código funcionar apenas nas situações de temperatura e pressão previstas. Em condições inesperadas, o mínimo a ser testado é o erro que retorna, código de retorno e mensagem, para ter certeza do ponto que o erro aconteceu, e para que não seja confundido com outro que aconteceu antes ou depois.

O código acima tem um bug bem “besta”, mas que acontece com frequência. Se não for enviado um número, o erro vai acontecer no logger e não no ponto que deveria acontecer. Então, se for testado somente o código de retorno 500, o teste não está completamente correto. Afinal, a exceção ocorrerá em outro ponto e a entrada não será salva (suponha que seja em qualquer lugar). Prontinho, agora você tem um falso positivo e um bug que vai ser bem difícil de achar.

Faça sempre validações de tipos e range de variável. Sempre bom normalizar seus dados, e mandar mensagens claras dos seus erros.

Aja como um engenheiro tentando prever todas as variáveis que podem gerar erro na aplicação, e não como um bombeiro que só vem apagar incêndios, diferente deles, apagar incêndios não vai te tornar um herói.

Seja objetivo nos seus testes

Não precisa fazer ambos asserts no mesmo teste.

Afinal, estará testando praticamente a mesma coisa sobre a mesma variável.

Seja assertivo nos seus testes

Continue com o exemplo anterior:

Busque sempre ser mais assertivo e específico possível. Fazer o assert só do tamanho do variável não é aconselhável. Se alterarem o nome para “Bobão”, o teste ainda vai passar, mas não seria nada legal isso ir para produção, né?

Relaxe um pouco com datas e timestamps (mas não muito)

Esse é realmente (e literalmente) um tópico à parte. Na maioria das vezes, é difícil fazer um assert preciso de data nos testes, afinal, em cada teste as datas mudariam. Nesse caso, você tem duas alternativas pra datas, (timestamp esquece ¯\_(ツ)_/¯):

  1. Forçar seus testes terem a mesma data;
  2. Fazer asserts dinâmicos de datas. Em uma aplicação que está rodando coisas de ontem, faz sentido fazer um now()-1 para testar.

Nesse caso é tudo bem opcional e vai depender da realidade da sua aplicação, já vi ambos casos rodarem bem, então não é uma receita de bolo.

Usar alguma validação de estrutura de data

No aiqfome, usamos JSON na comunicação dos nossos serviços, mas por exemplo, temos esse teste:

Top, mas o que acontece se adicionarmos no json o campo subtotal? O nosso teste continua passando. Como resolvemos isso? Usamos uma lib de validação de dados, para que, se um campo for alterado, removido ou adicionado o teste quebre e assim possamos manter a integridade das coisas. No caso do aiq, nossos testes estão em Python, então usamos o Cerberus pra fazer esse trabalho.

Testes automatizados são um assunto tão vasto ao ponto de serem tópicos de livros, então é dificil resumir tudo em um texto. Aqui tentei passar uma visão geral das nossas experiências no aiqfome, mas provavelmente voltaremos a falar sobre o assunto.

SUGESTÕES, RECLAMAÇÕES, DÚVIDAS E ELOGIOS

Por favor falar com o Clodoaldo. Ele tá sempre no twitter, instagram, face, e até no linkedin do aiq.

Mentira, o Crô é mó ocupado, pode me responder por aqui mesmo ou conversar comigo no Linkedin!

até a proxima!

--

--