Uma query de banco que roda em 30ms com 100 linhas pode dar timeout com 1 milhão. Os testes funcionais nunca vão detectar isso porque rodam um cenário por vez. Testes de performance simulam o tráfego concorrente que revela essas falhas: load testing para tráfego normal, stress testing para encontrar o ponto de ruptura, spike testing para picos súbitos. Soak testing expõe vazamentos de memória que só aparecem após horas.
Por que testes de performance importam
Um formulário de login que responde em 200ms está ótimo. Com 5 segundos, perde usuários. Com 30 segundos sob carga, derruba o servidor.
Bugs de performance costumam ser os mais difíceis de corrigir: exigem mudanças arquiteturais, não simples correções de código. Encontrá-los cedo faz diferença.
Falhas de performance comuns:- Queries de banco que funcionam com 100 linhas e dão timeout com 1 milhão
- Endpoints de API que aguentam 10 usuários concorrentes e falham com 100
- Vazamentos de memória que se acumulam após horas de uso
- Integrações com terceiros que viram gargalo sob carga
Tipos de testes de performance
Load testing
Simula a carga esperada em produção para verificar se o sistema performa dentro dos limites aceitáveis.
Pergunta: O sistema aguenta o tráfego normal? Exemplo: Nossa app tem 500 usuários simultâneos durante o horário comercial. Rode 500 usuários virtuais por 30 minutos e meça os tempos de resposta. Resultados aceitáveis:- Tempo de resposta no percentil 95 abaixo de 1 segundo
- Taxa de erro abaixo de 1%
- Sem vazamentos de memória
Stress testing
Empurra o sistema além dos limites para encontrar o ponto de ruptura.
Pergunta: Como o sistema se comporta quando sobrecarregado? Ele falha de forma controlada? Exemplo: Comece com 100 usuários, aumente 100 a cada minuto até o sistema quebrar. Observe quando os erros começam, como o sistema falha e se ele se recupera.Spike testing
Aumento massivo e súbito de carga, seguido de retorno ao normal.
Pergunta: O sistema aguenta picos súbitos de tráfego? Exemplo: Carga normal é de 100 usuários. De repente, salta para 1.000 por 2 minutos, depois volta para 100. Cenários preocupantes: Menções em redes sociais, matérias de jornal, flash sales.Soak testing (teste de resistência)
Carga sustentada por um período prolongado.
Pergunta: Vazamentos de memória ou degradação de performance se acumulam ao longo do tempo? Exemplo: 200 usuários simultâneos por 8 horas. Monitore uso de memória e tendências de tempo de resposta.k6: a ferramenta moderna de load testing
O k6 é a ferramenta de load testing mais acessível para QA: baseada em JavaScript, roda pelo CLI, integra com CI.
Instalação
# macOS
brew install k6
# Windows (winget)
winget install k6
# Docker
docker pull grafana/k6Seu primeiro load test
// load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';
// Configuração do teste
export const options = {
vus: 50, // Usuários virtuais
duration: '30s', // Rodar por 30 segundos
};
export default function() {
// Fazer uma requisição
const response = http.get('https://lab.becomeqa.com/api/products');
// Assertions
check(response, {
'status é 200': (r) => r.status === 200,
'tempo de resposta < 500ms': (r) => r.timings.duration < 500,
'tem produtos': (r) => JSON.parse(r.body).length > 0,
});
// Aguardar entre iterações (simula comportamento real do usuário)
sleep(1);
}Executar:
k6 run load-test.jsSaída:
✓ status é 200 100.00% ✓ 1500 ✗ 0
✓ tempo de resposta < 500ms 95.33% ✓ 1430 ✗ 70
✓ tem produtos 100.00% ✓ 1500 ✗ 0
http_req_duration..............: avg=185ms min=45ms med=160ms max=1.2s p(90)=350ms p(95)=480ms
http_reqs......................: 1500 49.91/sCenários de ramp-up
Mais realista do que atingir a carga total imediatamente:
export const options = {
stages: [
{ duration: '2m', target: 100 }, // Subir para 100 usuários em 2 minutos
{ duration: '5m', target: 100 }, // Manter 100 usuários por 5 minutos
{ duration: '2m', target: 200 }, // Subir para 200
{ duration: '5m', target: 200 }, // Manter 200 usuários
{ duration: '2m', target: 0 }, // Descer
],
};Testando um endpoint de API com autenticação
import http from 'k6/http';
import { check, group } from 'k6';
export const options = {
stages: [
{ duration: '1m', target: 50 },
{ duration: '3m', target: 50 },
{ duration: '1m', target: 0 },
],
thresholds: {
'http_req_duration': ['p(95)<500'], // 95% das requisições abaixo de 500ms
'http_req_failed': ['rate<0.01'], // Menos de 1% de erros
},
};
export function setup() {
// Login uma vez, retorna token para todos os usuários virtuais
const res = http.post('https://api.minhaapp.com/auth/login', JSON.stringify({
email: 'load-test@minhaapp.com',
password: 'SenhaLoadTest1',
}), { headers: { 'Content-Type': 'application/json' } });
return { token: JSON.parse(res.body).token };
}
export default function(data) {
const headers = {
'Authorization': `Bearer ${data.token}`,
'Content-Type': 'application/json',
};
group('Listar produtos', () => {
const res = http.get('https://api.minhaapp.com/products', { headers });
check(res, { 'produtos carregados': (r) => r.status === 200 });
});
group('Detalhe do produto', () => {
const res = http.get('https://api.minhaapp.com/products/1', { headers });
check(res, { 'detalhe do produto carregado': (r) => r.status === 200 });
});
sleep(Math.random() * 3 + 1); // Tempo de espera aleatório de 1 a 4 segundos
}Thresholds de performance
Defina critérios de aprovação/reprovação:
export const options = {
thresholds: {
// 95% das requisições devem completar abaixo de 500ms
'http_req_duration': ['p(95)<500'],
// Threshold para endpoint específico
'http_req_duration{name:products}': ['p(95)<300'],
// Menos de 0,1% de erros permitidos
'http_req_failed': ['rate<0.001'],
// Threshold de métrica customizada
'checkout_duration': ['p(90)<2000'],
},
};Se os thresholds não forem atingidos, o k6 sai com código não-zero e o CI falha automaticamente.
O que medir
Percentis de tempo de resposta:- p50 (mediana): 50% das requisições são mais rápidas que isso
- p90: 90% das requisições são mais rápidas que isso
- p95: 95% das requisições são mais rápidas que isso
- p99: A cauda lenta, o que os 1% piores experimentam
Integrando com CI
# GitHub Actions
performance-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Instalar k6
run: |
curl https://github.com/grafana/k6/releases/download/v0.50.0/k6-v0.50.0-linux-amd64.tar.gz -L | tar xvz
sudo mv k6-v0.50.0-linux-amd64/k6 /usr/local/bin
- name: Rodar load test
run: k6 run load-tests/api-load-test.js
env:
BASE_URL: ${{ secrets.STAGING_URL }}
- name: Upload dos resultados
uses: actions/upload-artifact@v4
if: always()
with:
name: k6-results
path: k6-results.jsonProblemas comuns de performance para investigar
Queries de banco lentas:- Monitore o tempo de execução das queries sob carga
- Queries N+1 (1 query por linha em vez de 1 no total)
- Índices ausentes
- Uso de memória crescendo ao longo do tempo sem diminuir
- Detectados em soak tests
- Conexões de banco acabam sob alta concorrência
- Erro: "too many connections"
- API externa que fica lenta sob carga
- Gateway de pagamento com rate limits
- Mesmos dados buscados do banco repetidamente: deveriam estar em cache
Resumo
| Tipo de teste | Propósito | Duração |
|--------------|-----------|---------|
| Load test | Verificar performance com carga normal | 30min a 2h |
| Stress test | Encontrar o ponto de ruptura | Até a falha |
| Spike test | Aguentar picos súbitos de tráfego | Picos curtos |
| Soak test | Detectar vazamentos de memória | Horas |
Fundamentos do k6:vus— usuários virtuaisduration— quanto tempo rodarstages— padrões de ramp-upthresholds— critérios de aprovação/reprovaçãocheck()— assertions por requisição
Testes de performance são separados dos testes funcionais: ferramentas diferentes, objetivos diferentes. Testes funcionais verificam correção; testes de performance verificam velocidade e confiabilidade sob carga. Os dois são necessários antes de fazer deploy.
→ Veja também: Testes de Performance com k6: O Primeiro Teste de Carga do Engenheiro QA | A Pirâmide de Testes Explicada para Engenheiros QA | Testes de API 101: Tudo que Todo Engenheiro QA Precisa Saber em 2026