Por que testar automaticamente?
Porque o custo de encontrar um bug em produção e muito maior do que encontra-lo antes do deploy.
Testes automatizados são código que verifica se o sistema faz o que se espera que ele faca. Em vez de testar manualmente cada funcionalidade a cada mudanca, o time escreve testes uma vez e os executa automaticamente toda vez que o código muda. O retorno aparece rapidamente: bugs são encontrados em segundos após serem introduzidos, não dias ou semanas depois em produção. Times que investem em testes automatizados entregam com mais velocidade e mais confianca. Times sem testes ficam cada vez mais lentos conforme o sistema cresce, porque cada mudanca requer retestes manuais extensos para garantir que nada quebrou.
A piramide de testes
Muitos testes unitários, alguns de integração, poucos E2E: o equilibrio entre velocidade e confianca.
A piramide de testes, proposta por Mike Cohn, descreve a distribuição ideal dos diferentes tipos de teste. Na base estão os unit tests: rápidos, baratos e em grande quantidade. No meio estão os integration tests: mais lentos e em menor quantidade. No topo estão os E2E tests: lentos, caros e em pequeno número. A piramide e inversamente proporcional ao custo de execução e manutenção. Muitos E2E tests criam uma suite lenta e fragil. Muitos unit tests sem integration tests dao falsa segurança de que os componentes funcionam juntos. O equilibrio entre os tres níveis e o que cria uma suite util e sustentável.
Unit tests na prática
Testam uma unidade isolada, rapidamente, sem dependências externas.
Um unit test verifica o comportamento de uma função, metodo ou classe de forma isolada, substituindo dependências externas por mocks ou stubs. Deve executar em milissegundos e não deve acessar banco de dados, rede ou sistema de arquivos. A regra básica e: se o teste e lento ou fragil, não e um bom unit test. Unit tests são especialmente valiosos para lógica de negócio complexa, algoritmos e casos de borda. Com bons unit tests, o time pode refatorar com confianca: se os testes continuam passando, o comportamento externo não mudou. Ferramentas populares: Jest (JavaScript), JUnit (Java), xUnit (C#), pytest (Python).
Integration tests
Testam a interação entre componentes reais, banco, serviços, filas.
Integration tests verificam se diferentes partes do sistema funcionam corretamente juntas. Em vez de mockar o banco de dados, eles usam um banco real (geralmente em container Docker). Em vez de mockar um serviço externo, testam contra uma versão real ou de staging. São mais lentos que unit tests mas detectam categorias de problemas que unit tests não pegam: queries SQL incorretas, problemas de serialização, comportamentos de transação e falhas de comunicação entre serviços. A regra geral e ter menos integration tests que unit tests, focando nas boundaries críticas do sistema: acesso ao banco, integração com APIs externas e interação entre bounded contexts.
E2E tests com Playwright
Simulam o usuário no browser, testando o fluxo completo do frontend ao banco de dados.
End-to-end tests simulam um usuário real interagindo com a aplicação no browser. Playwright, da Microsoft, e a ferramenta mais moderna para isso: suporta Chromium, Firefox e WebKit, tem uma API fluente, execução em paralelo e gravação de sessões para debug. Um E2E test abre o browser, navega para uma página, preenche formulários, clica em botões e verifica o que aparece na tela. Testam o sistema completo, do frontend ao banco de dados. São os testes mais caros de manter porque dependem da interface, que muda com frequência. Por isso devem ser reservados para os fluxos críticos: login, checkout, cadastro, fluxos de pagamento.
TDD: ciclo red-green-refactor
Escrever o teste antes do código e uma técnica que melhora o design e a cobertura simultaneamente.
Test-Driven Development e uma prática onde o teste e escrito antes do código de produção. O ciclo tem tres fases. Red: escrever um teste que falha porque a funcionalidade não existe ainda. Green: escrever o mínimo de código necessário para o teste passar. Refactor: melhorar o código mantendo os testes verdes. Esse ciclo forcado resulta em código mais modular, porque e difícil testar código com muitas dependências acopladas. Também resulta em cobertura alta naturalmente, sem precisar adicionar testes depois. TDD não e para todos os contextos, mas e especialmente valioso para lógica de negócio complexa e para código legado ao adicionar novas funcionalidades.
Test coverage e o que realmente importa
100% de cobertura não e o objetivo, cobrir lógica crítica sim.
Test coverage mede a porcentagem de linhas ou branches do código exercitadas pelos testes. E uma métrica util como indicador mínimo de qualidade, mas perigosa como meta absoluta. Times que perseguem 100% de cobertura escrevem testes sem assertivas uteis apenas para aumentar o número. O que importa e cobrir a lógica crítica: regras de negócio, cálculos financeiros, validações e fluxos de autenticação. Código trivial como getters simples e configurações pode ter cobertura baixa sem problema. Uma cobertura de 70 a 80% de código relevante com boas assertivas e mais valiosa que 100% de código trivial coberto por testes frageis.
Mocking e seus limites
Mocks isolam o que esta sendo testado, mas mocks em excesso mascaram problemas reais.
Mocking e a técnica de substituir dependências reais por objetos simulados que retornam respostas controladas. Permite testar lógica de negócio sem precisar de banco de dados ou serviços externos. O problema e quando os mocks divergem do comportamento real: se o mock de um repositório retorna dados perfeitos mas o repositório real tem problemas de query, os testes passam mas o sistema falha em produção. A regra e: use mocks para isolar a unidade sendo testada, mas cubra as boundaries com integration tests contra dependências reais. Mockar tudo e um sinal de design acoplado demais, não de bons testes.
Como começar em projeto legado
Adicionar testes em código legado sem testes e possível, com a estrategia certa.
Em código legado sem testes, a estrategia mais eficaz e adicionar testes characterization primeiro: testes que documentam o comportamento atual, sem julgamento sobre se e o comportamento correto. Isso cria uma rede de segurança antes de qualquer refatoração. A seguir, ao adicionar cada nova funcionalidade, escrevia-a com TDD. Ao corrigir cada bug, escreva o teste que reproduz o bug antes de corrigir. Com essa abordagem incremental, a cobertura cresce organicamente sem necessidade de parar o desenvolvimento para escrever testes retroativamente. O livro Working Effectively with Legacy Code de Michael Feathers e a referência definitiva para essa situação.
Resumo
Testes automatizados não são opções, são o que separa times que entregam rápido dos que entregam com medo.
Uma suite de testes bem construída e um ativo que cresce em valor com o tempo. Ela permite refatorar sem medo, lancar com confianca e detectar regressões antes que cheguem aos usuários. A piramide de testes guia a distribuição entre unit, integration e E2E. TDD melhora o design enquanto cria cobertura. Playwright cobre os fluxos críticos do usuário. A métrica de cobertura serve como indicador, não como meta absoluta. Em projetos legados, a abordagem incremental e a mais prática. Times que tratam testes como parte integrante do desenvolvimento, não como atividade opcional do final, entregam software melhor e com mais velocidade ao longo do tempo.
Tutoriais em Video
Learning Test-Driven Development (TDD), Dave Farley, GOTO 2022
When Test Driven Development (TDD) Gões Wrong, Dave Farley, GOTO 2021
The Art of Unit Testing, Roy Osherove & Dave Farley, GOTO 2021
JS Unit Testing Good Practices & Horrible Mistakes, GOTO 2013
Test Driven Development - What? Why? And How?
JavaScript Testing Introduction Tutorial, freeCodeCamp
Conceitos-chave
Piramide de testes
muitos unit tests na base alguns integration tests no meio poucos E2E no topo, equilibrio entre velocidade custo e confianca
Unit test
testa uma unidade isolada, rápido deterministico sem dependências externas
Integration test
testa interação entre componentes, banco real serviços reais, mais lento mas mais realista
E2E test
simula o usuário, Playwright Cypress, testa o fluxo completo
TDD
escrever o teste ANTES do código, ciclo red-green-refactor
Test coverage
percentual de código coberto, 100% não e o objetivo, cobrir lógica crítica
Testes Automatizados no Instagram
@bytebytego
Reels, Testes Automatizados
@bytebytego
Testes Automatizados no Facebook
Testes Automatizados no X (Twitter)
Links Uteis
O que devs dizem
Antes de adotar TDD, nosso ciclo de QA era um gargalo enorme. Depois de seis meses com TDD e Playwright para os fluxos críticos, as regressões caíram drasticamente. O melhor: posso refatorar qualquer parte do sistema sem medo porque a suite avisa imediatamente se algo quebrou.
O maior aprendizado foi que test coverage como meta absoluta e perigoso. A gente tinha 85% de cobertura e ainda assim bugs críticos escapavam. Quando focamos em cobrir lógica de negócio real em vez de percentual, a qualidade subiu de verdade.
Herdei um projeto legado sem nenhum teste. Comecei pelos characterization tests para documentar o comportamento atual. Em tres meses, com a abordagem incremental, tinhamos cobertura suficiente para refatorar com confianca. Não e rápido mas e o caminho certo.