Testes de Software
Um teste automatizado é uma afirmação executável sobre o comportamento do código: dado um estímulo, espera-se um resultado, e rodar o teste confronta essa expectativa com a realidade. A mecânica é simples e cabe numa frase. O que não é óbvio, e é onde mora quase toda a confusão, é por que alguém acumularia milhares dessas afirmações, quais escrever, e o que se ganha de fato com cada uma. Testar bem não é escrever muitos testes; é escrever os testes cujo retorno paga o que eles cobram.
Para que serve um teste
Section titled “Para que serve um teste”A primeira fonte de mal-entendido é tratar “testar” como uma coisa só, quando são pelo menos três finalidades distintas, que às vezes puxam em direções diferentes.
A finalidade mais óbvia é encontrar defeitos: rodar o código com entradas conhecidas e verificar se ele responde o esperado, para pegar o erro antes que o usuário pegue. É a verificação no sentido clássico, e é o que a palavra “teste” evoca de imediato.
A segunda, mais importante na prática e menos citada, é sustentar a mudança. Um sistema sem testes é um sistema que se tem medo de tocar: qualquer alteração pode quebrar algo distante em silêncio, e o custo de descobrir isso só em produção congela o código. Uma suíte de testes é a rede que devolve a coragem de refatorar, atualizar uma dependência, reescrever um módulo. Ela não existe para provar que o código está certo hoje; existe para avisar, amanhã, quando uma mudança o deixar errado. Essa é a razão pela qual sistemas que pretendem viver muito tempo investem em teste, e é também por que a manutenibilidade de um teste importa tanto quanto sua capacidade de pegar bug.
A terceira é pressionar o design. Escrever o teste antes do código, como propõe o TDD, força quem programa a usar a própria interface antes de implementá-la, e código difícil de testar quase sempre é código com um acoplamento que valia a pena desfazer. Aqui o teste é menos um verificador e mais uma ferramenta de projeto, e uma forma de especificação executável: o teste documenta, de maneira que não mente porque roda, o que a unidade promete fazer.
Essas finalidades convivem, mas não são a mesma coisa, e boa parte dos debates sobre testes, TDD sim ou não, unidade contra integração, mock demais ou de menos, é na verdade um desacordo sobre qual delas se está otimizando.
A régua: confiança sobre custo
Section titled “A régua: confiança sobre custo”Se há um único conceito que organiza todo o assunto, é este: todo teste compra confiança a um preço, e o preço tem mais de uma parcela. Há o custo de escrever o teste, o custo de rodá-lo (que se paga a cada execução, e define quão rápido é o ciclo de feedback), o custo de mantê-lo (quando o código muda, o teste muitas vezes muda junto) e o custo do sinal falso: um teste que quebra sem que exista bug, ou que fica verde apesar de um bug, corrói a própria utilidade da suíte, porque um sinal em que não se confia é ignorado.
O valor de um teste é a confiança que ele entrega dividida por essa soma de custos. Quase toda decisão sobre testes, qual escrever, quantos, em que nível, com quanto isolamento, é uma tentativa de maximizar essa razão. A pirâmide de testes é uma aposta sobre onde essa razão é melhor. O catálogo de tipos é um leque de instrumentos com razões diferentes. O efeito da linguagem é, no fundo, o efeito do compilador sobre o numerador e o denominador dessa fração. E a virada contemporânea, da qual a IA é o capítulo mais recente, é uma reavaliação de onde a razão compensa, feita à luz de sistemas distribuídos e de ferramentas que antes não existiam.
O mapa desta seção
Section titled “O mapa desta seção”O percurso vai da estrutura para os detalhes, e depois para o presente.
A pirâmide e as camadas trata da divisão clássica em unidade, integração e ponta a ponta, de por que essa divisão foi desenhada como uma pirâmide, e de quanto cada camada custa e entrega. É onde a régua de confiança sobre custo ganha forma concreta, e onde aparecem as rivais da pirâmide, o troféu e o favo de mel, que discordam justamente sobre qual camada paga melhor.
O catálogo de tipos sai do eixo unidade-integração-ponta a ponta e percorre os outros instrumentos: teste baseado em propriedades, teste de mutação, fuzzing, snapshot, contrato, além das categorias não funcionais como carga, segurança e acessibilidade. Cada um é uma resposta a uma pergunta que os testes de exemplo não respondem bem.
A linguagem molda o teste mostra como a escolha entre tipagem estática e dinâmica, e entre estilo funcional e imperativo, muda o que precisa ser testado e como. O compilador é o primeiro conjunto de testes, e o que ele já prova é o que não é preciso testar à mão.
A virada contemporânea e a IA cobre o que mudou de 2020 para cá: o recuo do mock pesado e do dogma de unidade, a migração de Selenium para Playwright, o teste em produção, e a camada mais nova, a geração de testes por modelos de linguagem, com o que ela promete e a armadilha que ela traz.
O objetivo, ao fim, é que “isso pede um teste de integração, não de unidade” ou “esse teste passou mas não afirma nada” deixem de ser jargão e virem afirmações que você sabe pesar.
Palavras-chave
Section titled “Palavras-chave”Conceitos: confiança sobre custo, ciclo de feedback, oráculo, regressão, especificação executável, manutenibilidade, sinal falso Finalidades: encontrar defeito, sustentar mudança, pressionar o design, documentar comportamento Práticas: TDD, teste de unidade, teste de integração, teste ponta a ponta Temas da seção: pirâmide de testes, catálogo de tipos, efeito da linguagem, geração por IA