Introdução
Testar um sistema não é apenas “rodar o programa e ver se não quebrou”. Formalmente, testes de software é o processo de avaliar um sistema para encontrar diferenças entre o comportamento esperado e o real, e construir confiança de que o sistema faz o que deveria fazer.
Duas noções que não podem ser confundidas:
- Verificação: Are we building the product right? O software está de acordo com a especificação/design? É o território dos testes técnicos (unitários e integração)
- Validação: Are we building the right product? O software resolve o problema real do negócio? É o território de aceitação, UAT, testes exploratórios.
Usando um caso real de testes para entender as duas noções na prática: GetDiferencaDataEmMeses_DeveRetornarDiferencaCorreta
- Verificação: a função implementa corretamente a regra de cálculo de diferença em meses.
- Validação: confirmar com a área de negócio que essa métrica é, de fato, a correta para aquele cálculo de benefício, o teste automatizado sozinho não garante isso.
Por que testamos: o custo crescente do erro
O argumento central é econômico: o custo de corrigir um defeito cresce exponencialmente quanto mais tarde ele é descoberto (o clássico "custo crescente do erro", popularizado por Boehm).
No domínio do usuário (BPO previdenciário/fiscal): um bug no cálculo de GetDiferencaAnos (que define elegibilidade a um benefício) encontrado por um teste unitário custa minutos. O mesmo bug encontrado em produção pode significar cálculo errado de benefício para centenas de participantes, retrabalho manual, risco regulatório (e-Financeira é fiscalização da Receita Federal) e dano de confiança.
Os três pilares de todo teste
Testar é uma atividade de equilíbrio entre três forças:
- Correção: o sistema faz o que deveria fazer.
- Confiança: o quanto a suíte de testes permite mudar o código sem medo. Esse é o verdadeiro ROI de testes: não é "achar bugs", é permitir mudança segura.
- Custo: tempo para escrever, rodar e manter os testes. Testes mal escritos (frágeis, lentos, obscuros) podem custar mais do que valem.
Daqui vem um princípio que vai aparecer no curso inteiro: nem todo teste possível vale a pena escrever. Testar é otimização sob restrição de tempo, não busca por cobertura de 100%.
Gestão da Qualidade: QA vs. QC
Gestão da Qualidade é o guarda-chuva: tudo que a organização faz para direcionar e controlar qualidade. Dentro dela, duas disciplinas complementares:
| Garantia de Qualidade (QA) | Controle de Qualidade (QC) | |
|---|---|---|
| Foco | Processo | Produto |
| Natureza | Preventiva | Detectiva |
| Pergunta | Estamos seguindo um processo que tende a gerar poucos defeitos? | Este artefato específico tem defeitos? |
| Atividades | Padrões, auditoria de processo, causa raiz, retrospectivas | Teste (unitário/integração/e2e), inspeção, code review |
| Efeito no tempo | Muda a curva de defeitos pra baixo ao longo dos releases | Atividades distribuídas ao longo de todo o ciclo ("mais à esquerda" — shift-left) |
QC sem QA vira jogo infinito de achar bug (o processo continua gerando os mesmos tipos de defeito todo sprint). QA sem QC é teoria sem verificação (melhora o processo "no papel", sem dado real de que funcionou). Uma retroalimenta a outra.
A distinção QA/QC não é arbitrária, ela vem de um modelo mais amplo e bem antigo na gestão da qualidade, o Custo da Qualidade (Cost of Quality, Crosby/Juran), que divide todo investimento em qualidade em quatro categorias:
| Categoria | O que é | Exemplo em software | Relação |
|---|---|---|---|
| Custos de Prevenção | Evitar que o defeito aconteça | Treinamento, revisão de requisito, definição de padrão de código | = QA |
| Custos de Avaliação | Encontrar o defeito antes de ir para produção | Testes automatizados,code review, inspeção | = QC |
| Custos de Falha Interna | Corrigir defeito encontrado antes do release | Retrabalho, re-teste, bug encontrado em homologação | Consequência de QC fraco |
| Custos de Falha Externa | Corrigir defeito encontrado depois do release | Incidente em produção, suporte, retrabalho de cálculo de benefício, multa regulatória | O topo da curva de custo crescente do erro (veja o gráfico acima) |
O insight gerencial do modelo: gastar mais em Prevenção (QA) reduz Avaliação + Falha Interna + Falha Externa, com retorno maior que linear, é por isso que organizações maduras investem proporcionalmente mais em QA do que em QC pura, mesmo QC sendo a atividade mais visível (é a que "acha os bugs").
Uma confusão muito comum no mercado
Vale um alerta prático: na indústria, é extremamente comum um "time de QA" que, na prática, só faz QC (só testa o produto pronto) sem nenhum mandato real sobre processo. Isso não é um erro terminológico inofensivo: uma organização que chama sua função de teste de "QA" mas nunca faz análise de causa raiz nem muda processo está, na prática, sem QA nenhuma — só QC. O sintoma típico: os mesmos tipos de bug reaparecem release após release, porque ninguém fecha o loop.
O ciclo fechado, exemplo aplicado.
Juntando com o exemplo de causa raiz já visto:
- QC encontra: um teste de integração (ou, pior, produção) acusa cálculo de benefício incorreto.
- RCA aponta a causa raiz: regra de negócio mal especificada antes da codificação.
- QA age no processo: passa a exigir revisão de requisito com 2 aprovadores de negócio antes de qualquer commit de regra de cálculo.
- QC mede o resultado: nos sprints seguintes, a taxa de defeitos dessa categoria cai — e é esse dado (não a opinião de que "o processo melhorou") que valida se a ação de QA funcionou.
Sem o passo 4, você não sabe se a mudança de processo realmente ajudou — é só teoria. Sem o passo 3, você fica reagindo ao mesmo tipo de bug para sempre.
Causa raiz e o Princípio de Pareto
O fluxo de QA na prática: defeito encontrado → análise de causa raiz (5 porquês, diagrama de Ishikawa) → ação no processo → menos defeitos daquele tipo no futuro.
Aplicando Pareto (regra 80/20): atacar só as duas primeiras causas já endereça a maioria dos defeitos. A decisão gerencial correta não é "escrever mais testes genéricos" — é ação de processo cirúrgica: revisão de requisito com o time de negócio antes de codificar regras de cálculo (ataca a causa #1), e checklist obrigatório de casos de borda de data para qualquer função que manipule datas (ataca a causa #2).
Aprofundando: a técnica dos 5 Porquês
Exemplo aplicado (hipotético, mas realista para o domínio previdenciário):
- Por que o cálculo de benefício retornou valor errado para o participante X? → Porque a função somou saldos de dois vínculos como se fossem um só.
- Por que ela somou os dois vínculos? → Porque o código assume implicitamente que cada participante tem só um vínculo ativo por período.
- Por que essa suposição foi codificada assim? → Porque o requisito original não mencionava o caso de múltiplos vínculos simultâneos.
- Por que o requisito não mencionava isso? → Porque a área de negócio que escreveu o requisito não foi consultada sobre esse cenário (raro, mas existente).
- Por que ninguém consultou a área de negócio sobre cenários raros? → Porque não há uma etapa formal de revisão de requisito com checklist de casos de borda antes da codificação.
A causa raiz real (passo 5) é de processo, não de código — "o dev esqueceu" (uma leitura preguiçosa do passo 1) seria a resposta errada se parássemos ali.
Armadilha comum: parar no primeiro "porquê" plausível e culpar uma pessoa em vez do processo. Isso é RCA malfeito. Você "resolve" repreendendo ou trocando uma pessoa, e o mesmo tipo de bug reaparece com o próximo desenvolvedor, porque a causa real (ausência de processo) nunca foi tocada.
Diagrama de Ishikawa (espinha de peixe)
Categoriza causas possíveis antes de investigar, para não convergir cedo demais numa hipótese única. Adaptação clássica dos "6M" para software:
| Categoria | Pergunta | Exemplo no domínio |
|---|---|---|
| Método/Processo | O processo de desenvolvimento permitiu o defeito? | Falta de revisão de requisito |
| Pessoas | Faltou conhecimento/treinamento? | Novo dev não conhecia a regra de vínculos múltiplos |
| Ferramentas | A ferramenta/framework contribuiu? | ORM que esconde uma query N+1 |
| Requisitos/Entrada | A especificação era ambígua ou incompleta? | Requisito não cobria vínculo duplo |
| Ambiente | Configuração de ambiente influenciou? | Fuso horário diferente em produção vs. dev |
| Dados | Dado de produção tinha formato inesperado? | Campo de data vindo nulo de um sistema legado |
O efeito (o defeito) fica na "cabeça do peixe"; cada categoria vira uma "espinha" com possíveis causas listadas, até achar a raiz real.
Pareto: de onde vem, e uma armadilha
O princípio vem de Vilfredo Pareto (economista que observou que boa parte da terra na Itália pertencia a uma pequena fração da população) — Juran aplicou à qualidade como "os poucos vitais vs. os muitos triviais" (vital few vs. trivial many).
Armadilha gerencial: Pareto ordena por frequência, não necessariamente por severidade/custo. Uma causa raiz que aparece em 5% dos defeitos mas gera um incidente regulatório grave (ex.: erro fiscal que atrasa a entrega da e-Financeira) pode merecer prioridade maior que uma causa de 40% que só gera retrabalho interno barato. A regra prática correta: construa o Pareto por impacto (frequência × custo/severidade), não só por contagem bruta.
Fechando o loop: como saber se a ação de RCA funcionou
Depois de implementar a ação de processo (ex.: checklist de revisão de requisito), é preciso voltar a medir a mesma categoria de causa raiz nos próximos releases. Se a frequência não caiu, duas hipóteses: (1) a causa raiz identificada estava errada, ou (2) a ação de processo não foi realmente seguida na prática (processo no papel ≠ processo em execução) — o que puxa direto para o ponto já visto de que QA sem QC é teoria sem verificação.
Visão gerencial: garantindo testes eficientes no time
Três camadas resolvem isso: quando no processo, o que exigir estruturalmente, e como medir se está funcionando.
Regra prática: o caso de teste de aceitação é escrito no mesmo dia que o requisito, não depois que o código existe.
O que exigir estruturalmente
- Definition of Done inclui teste. Uma história não está "pronta" sem teste automatizado correspondente.
- Code review cobre o teste, não só a implementação. O revisor pergunta: esse teste falharia se eu reintroduzisse o bug?
- CI como gate, não como relatório. PR com teste quebrando não mergeia (branch protection).
Como medir sem teatro de métricas
Cobertura de código (%) como meta vira teatro — testes que exercitam a linha sem afirmar nada relevante. Métricas mais honestas:
- Taxa de escape de defeito — quantos bugs chegaram em produção vs. foram pegos antes.
- Flaky test rate — testes que falham/passam aleatoriamente corroem a confiança no CI mais rápido que a ausência de testes.
- Tempo de execução da suíte — suíte lenta = time para de rodar localmente = shift-left morre na prática.
- Cobertura entra como sinalizador de risco, nunca como meta isolada de OKR.
Resumo: testes eficientes vêm de integrar teste como parte indissociável da definição de pronto desde o requisito, fechando o loop com análise de causa raiz dos defeitos que escaparem.
Estudo de caso: o Problema do Triângulo
Este é o exercício clássico de design de casos de teste (Glenford Myers, The Art of Software Testing). Especificação: um programa recebe 3 inteiros (lados) e responde escaleno, isósceles ou equilátero.
A armadilha pedagógica: a maioria escreve apenas 3 casos (um por classificação) e considera a suíte completa. Isso falha porque:
- A especificação nunca disse que a entrada é sempre um triângulo válido — e se a soma de dois lados for menor que o terceiro (desigualdade triangular violada)?
- O valor-limite exato, onde a soma de dois lados é igual ao terceiro (caso degenerado, "linha reta"), é onde bugs costumam viver.
- Entrada inválida de domínio (zero, negativo) nem é uma pergunta geométrica — é validação de entrada.
- Assimetria de implementação: um bug clássico é checar
a==be esquecerb==cisoladamente — por isso isósceles precisa de 3 variações (qual par é igual), não 1.
Suíte reconstruída — "efetiva" (encontra os bugs comuns) e razoavelmente "eficiente" (sem redundância boba):
| # | a | b | c | Esperado | Categoria |
|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | Escaleno | válido, caso geral |
| 2 | 2 | 2 | 3 | Isósceles | 1º e 2º iguais |
| 3 | 2 | 3 | 2 | Isósceles | 1º e 3º iguais |
| 4 | 3 | 2 | 2 | Isósceles | 2º e 3º iguais |
| 5 | 5 | 5 | 5 | Equilátero | todos iguais |
| 6 | 1 | 2 | 10 | Inválido | soma < terceiro lado |
| 7 | 1 | 2 | 3 | Inválido | soma = terceiro (valor-limite) |
| 8 | 0 | 5 | 5 | Inválido | lado zero |
| 9 | -1 | 5 | 5 | Inválido | lado negativo |
O ponto central: "efetivo" e "eficiente" não vêm de cobrir as saídas possíveis, vêm de pensar em como a implementação pode estar errada, ponte direta para as técnicas formais (particionamento de equivalência e análise de valor-limite).



Top comments (0)