Módulo 2 · Ciclo Comum · IN02 · Aula 9 de 11
Testes e Automação
Refatoração e requisitos não funcionais guiados por métricas — complexidade, cobertura e desempenho, tudo local com npm
🔧 Refatoração
🧠 Complexidade ciclomática
📊 Coverage
🧹 jscpd
🔗 madge
⚡ autocannon
⏱️ Daily — 15 Minutos
O que você fez? O que vai fazer? Algum impedimento?
15:00
✅ O que fiz 🎯 O que vou fazer 🚧 Impedimentos 🧪 Cobertura atual
📋 Agenda da Aula 9
Estrutura e objetivos da aula de hoje

🕐 Bloco 1 — Autoestudo (revisão e dúvidas)

Recap do material — code smells, complexidade ciclomática, cobertura, duplicação e RNFs mensuráveis.

🕑 Bloco 2 — Instrução (Professor)

Refatoração guiada por métricas: medir com ESLint, jscpd e Jest, refatorar e provar a melhora — tudo local.

🕒 Bloco 3 — Almoço

Pausa para refeição.

🎯 Bloco 4 — Desenvolvimento (Projeto)

Medir o projeto, eleger os 2 piores pontos, refatorar e registrar as métricas antes/depois no MR.

🗺️ Onde estamos no Módulo 2
Aula 9 de 11 · Testes e Automação
5
Back-end com Express + TS
Setup, rotas, server
6
CRUD via HTTP + zod
Validação, DTOs — e os primeiros testes
7
EJS — SSR
Views server-side
8
Fetch no cliente
Front consumindo a API
9
Testes e Automação ← você está aqui
Refatoração, métricas e RNFs locais
10
Front-End III — CSS/JS avançado
Polimento da view
11
Mergulhando nas Redes
TCP/IP, DNS, CDN e resiliência

🎯 Objetivo da Aula 9

Sair com o projeto medido e melhorado: complexidade e duplicação reduzidas nos piores pontos, cobertura com threshold local e um baseline de desempenho — com a suite verde provando que nada quebrou.

Vocês já testam — agora vamos usar os testes
De escrever testes a medir e melhorar a qualidade do código

✅ O que vocês já fazem desde a aula 6

Jest nos services e helpers, supertest nos controllers, AAA, mocks do repository. A suite existe e roda — isso não é o assunto de hoje.

🤔 A pergunta de hoje

O código funciona — mas ele é bom? Funcionar é requisito funcional. Ser legível, simples, rápido e sustentável é requisito não funcional.

📐 RNF se mede, não se opina

Complexidade ciclomática, % de duplicação, cobertura com threshold, latência p99. Cada um vira um número — e número dá para comparar antes e depois do refactor.

🧰 Tudo local, tudo npm

eslint, jest --coverage, jscpd, madge, autocannon. Um npx e pronto — nada de servidor, nada de CI. A máquina de vocês é o laboratório.

Code smells — quando o código pede refactor
Sinais de que funciona hoje, mas vai doer amanhã
SMELL
📜 Função longa
Mais de ~30 linhas fazendo 3 coisas. Difícil de testar e de nomear.
cura: extrair função
SMELL
👯 Código duplicado
Mesmo trecho em 2+ lugares. Bug consertado em um continua vivo no outro.
cura: extrair helper/service
SMELL
🏋️ Controller gordo
Regra de negócio no controller. Só dá para testar via HTTP.
cura: mover para o service
SMELL
🪜 Ifs aninhados
3+ níveis de indentação (arrow code). Complexidade explode.
cura: guard clauses
SMELL
🔢 Magic numbers
total * 0.9 — 0.9 é o quê? Desconto? Taxa? Ninguém sabe.
cura: constante nomeada
SMELL
🎭 Nome mentiroso
getUser() que também cria, atualiza e envia e-mail.
cura: renomear ou dividir

🥇 Regra de ouro da refatoração

Refatorar = mudar a estrutura sem mudar o comportamento. Quem prova que o comportamento não mudou é a suite de testes: verde antes, refactor pequeno, verde depois. Sem suite verde, não é refactor — é aposta.

O que é complexidade ciclomática? A intuição
Suas funções são trajetórias — cada bifurcação (if) adiciona um caminho independente

Corredor reto

sem if — só executa direto
1 trajeto Complexidade 1 · 1 teste

Uma bifurcação

if / else — 2 jeitos de atravessar
if? sim não Complexidade 2 · 2 testes

Bifurcações encadeadas

if / else if / else — 3 jeitos
if? if? Complexidade 3 · 3 testes

🚗 Analogia do GPS

Quantos trajetos diferentes existem da sua casa até o Inteli? Sem cruzamentos, um só. Cada cruzamento com decisão cria um trajeto novo. Para conhecer a cidade inteira, você precisa percorrer cada trajeto pelo menos uma vez — no código, isso é um teste por caminho.

💡 A definição em uma frase

Complexidade ciclomática é o número de trajetos independentes da entrada à saída da função. Cada if que você escreve é uma promessa silenciosa: "alguém vai precisar de mais um teste".

Complexidade ciclomática — a métrica nº 1
Agora o número exato: como o ESLint conta os trajetos (McCabe, 1976)
services/frete.service.ts

🧮 Como conta

Começa em 1 e soma 1 para cada if, else if, for, while, case, catch, &&, || e ?:. O resultado é o número mínimo de testes para cobrir todos os galhos.

1–5saudável
6–10atenção
>10refatore já

🎯 Por que importa

Complexidade alta = mais caminhos = mais testes necessários = mais lugares para o bug se esconder. É o RNF de manutenibilidade em forma de número.

Medindo com ESLint — biblioteca npm, zero servidor
A regra complexity transforma a métrica em aviso automático
.eslintrc.json & terminal

🧠 Duas métricas irmãs

  • complexity — ciclomática: quantos caminhos a máquina percorre
  • sonarjs/cognitive-complexity — cognitiva: quão difícil é para um humano ler (aninhamento pesa mais)

⚡ Feedback em segundos

Roda no terminal com npx eslint src/ e no editor enquanto você digita. O limite (8, 10) é da equipe — o que passa do limite entra na lista de refactor do Bloco 4.

Refatoração na prática — antes e depois
Guard clauses derrubam aninhamento e complexidade
services/desconto.ts — refactor

🔧 Técnicas do dia

  • Guard clause / early return — trate o caso inválido e saia
  • Extrair função — cada pedaço com nome próprio
  • Substituir condicional por mapaTAXAS[tipo]
  • Extrair constante — mata o magic number

🔁 O processo, sempre igual

npm test verde → refactor pequenonpm test verde → npx eslint para ver a métrica cair → commit. Passos curtos: se quebrar, o suspeito é o último passo.

Red, Green, Refactor — hoje moramos no terceiro passo
O ciclo que vocês conhecem, com o foco que faltava
🔴
RED
Escreva o teste primeiro. Ele falha — porque o código nem existe ainda.
🟢
GREEN
Implemente o mínimo para o teste passar. Feio é OK.
🔧
REFACTOR
Melhore o desenho com a rede de segurança verde. É aqui que a métrica cai.

💡 O passo que todo mundo pula

Na pressa, o ciclo vira Red → Green → próxima feature. O débito acumula até o código travar. Hoje o REFACTOR deixa de ser opcional: ele tem métrica, tem meta e tem entrega.

🎯 A suite de vocês é o GREEN permanente

Os testes escritos desde a aula 6 são a rede de segurança. Cada refactor de hoje roda contra eles: comportamento igual, estrutura melhor, número menor.

As 4 métricas de cobertura — o que cada uma mede
Por que 100% de Lines ≠ 100% de Branches — e qual delas não deixa você mentir

🔬 Mesmo código, resultados diferentes

Só este teste rodou: desconto({'{'}vip: false{'}'}, 100)

function desconto(user, total) {
  if (user.vip) return total * 0.8;  ← nunca executou
  return total;
}

⚠️ O bug que 100% Lines esconde

Se o galho user.vip = true nunca foi testado, a lógica de desconto VIP pode estar errada — e o relatório ainda mostra verde em Lines e Functions.

Métrica O que conta No exemplo Peso
Lines Linhas físicas tocadas ao menos 1x 3/3 = 100%
Stmts Instruções executadas (1 linha pode ter várias) 2/3 = 67% ⭐⭐
Functions Funções chamadas ao menos 1x 1/1 = 100% ⭐⭐
Branches Cada galho de if/else, ternário, ??, && 1/2 = 50% ⭐⭐⭐

🎯 Qual usar como meta?

Branches é a mais honesta: obriga você a cobrir cada decisão, não só passar pela linha. Configure no jest.config: branches ≥ 70% e lines ≥ 80% — o threshold que falha antes de virar dívida técnica.

Coverage — métrica que mente sem você
100% de cobertura ≠ código correto
npm run test:cov

📊 As 4 dimensões

  • Statements — instruções executadas
  • Branches — galhos de if/else testados
  • Functions — funções chamadas
  • Lines — linhas físicas tocadas

🚧 Threshold local no jest.config

"coverageThreshold": {
  "global": { "branches": 70, "lines": 80 }
}

Abaixo disso, npm run test:cov falha na sua máquina — o portão de qualidade é local.

⚠️ Coverage não garante

Linha tocada sem assert não testa nada. Use coverage para achar buracos, nunca como troféu.

jscpd + madge — duplicação e dependências
Dois npx que revelam o que o olho não vê
terminal — análise local

🧹 jscpd — copy/paste detector

Acha trechos duplicados por token, não por texto — pega até cópia com variável renomeada. Duplicação é o smell mais caro: bug corrigido em um lugar continua vivo no outro.

🔗 madge — grafo de dependências

--circular denuncia ciclos (A importa B que importa A): impossíveis de testar isolados e de entender separados. Service e repository em ciclo = camadas vazando.

🎯 Metas da equipe

Duplicação < 5% · ciclos = 0. Rodem nos dois sentidos: antes do refactor (diagnóstico) e depois (prova).

RNF de desempenho — autocannon local
"É rápido?" vira "p99 < 100 ms com 50 conexões" — testável na sua máquina
terminal — load test local

📏 Percentis, não média

A média esconde os piores casos. p50 = experiência típica; p99 = a do usuário azarado. RNF sério se escreve em percentil: "p99 < 100 ms".

🔁 Baseline antes, prova depois

Rode antes do refactor e guarde os números. Rode depois e compare. Refatorar não pode deixar o endpoint mais lento — agora você tem como saber.

🔍 Latência explodiu?

O gargalo quase sempre é a query. Volte ao EXPLAIN das aulas de banco — índice faltando aparece no p99 primeiro.

RM-ODP — As 5 Visões do Sistema
ISO/IEC 10746 · Qualidade nas 5 visões
🏢 Enterprise
Qualidade do produto
📋 Information
Métricas como contrato
⚙️ Computational
Refatoração + RNFs testáveis
🔧 Engineering
npm scripts + hooks locais
💻 Technology
Jest, ESLint, jscpd, autocannon

Esta aula: as 5 visões atravessadas pelo eixo de qualidade mensurável — métricas locais dão segurança para refatorar.

Esta Aula: Qualidade
RM-ODP · RF, RNF e Artefato — 8 Eixos de confiança

📌 Requisito Funcional

Refatorar o código mantendo o comportamento observável — provado pela suite de testes rodando verde antes e depois.

📦 Artefato

  • 🔧 Código refatorado com suite verde
  • 📊 Relatório de métricas antes/depois
  • Baseline de desempenho (autocannon)

⚖️ RNF — 8 Eixos ISO/IEC 25010

MANT Manutenibilidade✅ Complexidade ≤ 8 · duplicação < 5%
CONF Confiabilidade✅ Suite verde pós-refactor
TEST Testabilidade✅ Cobertura com threshold local
DES Desempenho✅ p99 medido com autocannon
PORT Portabilidade→ Métricas reproduzíveis em qualquer máquina
🧪
Código medido, refatorado, provado!
Você sabe agora medir a saúde do código com ferramentas npm locais, achar os piores pontos e refatorá-los com a suite de testes de guarda. Próxima parada: polir o front com essa rede de segurança.
📦 Entrega da Aula 9
Refatorar os 2 piores pontos do projeto com tabela de métricas antes/depois (complexidade, duplicação, cobertura) + suite verde
✅ Code smells
✅ Refatoração
✅ Complexidade ciclomática
✅ ESLint local
✅ Coverage threshold
✅ jscpd · madge
✅ autocannon
Próxima aula: Aula 10 — Front-End III · CSS e JavaScript avançado
🧩 Atividade · Diagnóstico em Equipe
Grupos de 6–7 · cada integrante roda uma ferramenta diferente · compartilhe o resultado com a equipe 7 ferramentas = 7 funções — grupo de 6? o sétimo repete a que achar mais crítica
🔍 Code Smells
npx eslint src/

Qual arquivo tem mais warnings? Liste os 3 piores.

🧮 Complexidade
npx eslint src/ --rule "complexity:[warn,5]"

Quantas funções passam de 5 caminhos? Qual é a mais alta?

⚙️ ESLint local
npm i -D eslint-plugin-sonarjs

Configure o .eslintrc com sonarjs. Quantos problemas novos?

🔧 Refatoração
identifique + aplique guard clauses

Pegue a função mais complexa e mostre antes/depois.

📊 Coverage
npm run test:cov

Qual % de branches abaixo de 80%? Qual controller tem menos cobertura?

🔁 jscpd · madge
npx jscpd src && npx madge --circular src

% de duplicação — há dependência circular?

autocannon
npx autocannon -c 50 -d 10 localhost:3000/api/…

Req/s e p99 — passa de 100 ms?

⏱ 20 min · rode, anote e explique o que encontrou para a equipe