Testes de Regressão: Garantindo Qualidade Contínua

Introdução a Qualidade de Software · 6 de julho de 2026

📖 6 min de leitura

O Que São Testes de Regressão?

Testes de regressão são executados para garantir que mudanças recentes no código (novas funcionalidades, bug fixes, refactoring) não introduziram novos defeitos ou quebraram funcionalidades existentes.

Quando Executar Regressão

Situação Recomendação
Antes de cada release Suite completa
Após hotfix Smoke + área afetada
Antes de deploy Critical path
Semanalmente (CI) Suite rápida
Sob demanda Após mudanças críticas

Estratégias de Seleção de Testes

1. Regressão Completa

Executa toda a suite de testes.

Quando usar:

  • Releases major
    1. Mudanças arquiteturais
    2. After database migration
    3. Final gate para produção

    2. Regressão Parcial (Seletiva)

    Seleciona subconjunto baseado em mudanças.

    # Exemplo: Selecionar testes por área afetada
    def get_affected_tests(changed_files):
        """Retorna testes que devem ser executados"""
    
    

    module_to_tests = {
    'src/auth/': ['tests/auth/*.py', 'tests/conftest.py'],
    'src/payment/': ['tests/payment/*.py'],
    'src/cart/': ['tests/cart/.py', 'tests/checkout/.py'],
    }

    tests = set()
    for changed_file in changed_files:
    module = extract_module(changed_file)
    if module in module_to_tests:
    tests.update(module_to_tests[module])

    return tests

    # Executar apenas testes afetados
    affected_tests = get_affected_tests(get_changed_files())
    pytest.main(affected_tests)

    3. Regressão Baseada em Risco

    Prioriza por risco de impacto.

    Prioridade Critério Execução
    Crítica Fluxos de pagamento, auth Sempre
    Alta Features principais Antes de cada release
    Média Features secundárias Semanalmente
    Baixa Edge cases Mensalmente

    4. Regressão Híbrida

    Combina múltiplas estratégias.

    # strategy: Hybrid Regression
    
    

    # Nivel 1: Critical (sempre)

    1. tests/auth/login*.py

    2. tests/auth/logout*.py

    3. tests/payment/checkout*.py

    4. tests/smoke/*.py


    # Nivel 2: Based on changes
    1. get_affected_tests()


    # Nivel 3: Risk-based
    1. tests/high_risk_features*.py


    # Nivel 4: Full (releases only)
    1. tests/full_suite/*.py


Automação de Regressão

Framework Ideal

regression_suite/
├── conftest.py              # Setup global
├── pytest.ini               # Configuração
├── requirements.txt         # Dependências
│
├── core/
│   ├── __init__.py
│   ├── base_page.py         # Page Object base
│   ├── api_client.py        # Cliente API
│   └── database.py          # Helpers de DB
│
├── pages/                   # Page Objects
│   ├── login_page.py
│   ├── dashboard_page.py
│   └── checkout_page.py
│
├── api/                     # API Tests
│   ├── test_auth.py
│   ├── test_products.py
│   └── test_orders.py
│
├── ui/                      # UI Tests
│   ├── test_login.py
│   ├── test_checkout.py
│   └── test_profile.py
│
├── smoke/                   # Smoke Tests
│   └── test_critical_path.py
│
├── data/                    # Data files
│   └── users.json
│
└── reports/                 # Relatórios
    └── .gitkeep

Page Object Pattern

# pages/base_page.py
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class BasePage:
def __init__(self, driver):
self.driver = driver
self.wait = WebDriverWait(driver, 10)

def click(self, locator):
self.wait.until(EC.element_to_be_clickable(locator)).click()

def send_keys(self, locator, text):
element = self.wait.until(EC.presence_of_element_located(locator))
element.clear()
element.send_keys(text)

def get_text(self, locator):
return self.wait.until(EC.presence_of_element_located(locator)).text

def is_visible(self, locator):
try:
return self.wait.until(
EC.visibility_of_element_located(locator)
).is_displayed()
except:
return False

# pages/login_page.py
from selenium.webdriver.common.by import By

class LoginPage(BasePage):
URL = "https://exemplo.com/login"

EMAIL = (By.ID, "email")
PASSWORD = (By.ID, "password")
LOGIN_BUTTON = (By.ID, "login-button")
ERROR_MESSAGE = (By.CLASS_NAME, "error-message")

def load(self):
self.driver.get(self.URL)
return self

def login(self, email, password):
self.send_keys(self.EMAIL, email)
self.send_keys(self.PASSWORD, password)
self.click(self.LOGIN_BUTTON)
return self

def get_error(self):
return self.get_text(self.ERROR_MESSAGE)

Execução Paralela

# pytest.ini
[pytest]
addopts = -n auto --dist loadscope
# -n auto: usa todas CPUs disponíveis
# --dist loadscope: agrupa testes por scope
# GitHub Actions
name: Regression Tests

on:
schedule:
- cron: '0 6 1' # Toda segunda 6h

jobs:
regression:
runs-on: ubuntu-latest
strategy:
matrix:
shard: [1, 2, 3, 4]

steps:
- uses: actions/checkout@v4

- name: Run test shard ${{ matrix.shard }}
run: |
pytest tests/
--dist loadscope
--maxprocesses 4
--split=${{ matrix.shard }}/4


Manutenção da Suite

Identificando Testes Obsoletos

# script: identify_obsolete_tests.py
import subprocess
from datetime import datetime

def analyze_test_usage():
"""Analisa quais testes não foram executados ou falham sempre"""

results = []

# 1. Testes sem execution recent
git_log = subprocess.run(
['git', 'log', '--oneline', '--all', '--', 'tests/'],
capture_output=True,
text=True
).stdout

# 2. Testes que sempre falham
# 3. Testes duplicados
# 4. Cobertura redundante

return results

# Gerar relatório
report = analyze_test_usage()
print("Testes para revisão:")
for test in report:
print(f" - {test['name']}: {test['reason']}")

Indicadores de “Code Smell” em Testes

# PROBLEMA: Teste faz muito
def test_criar_pedido_completo():
    # Setup (50 linhas)
    # Login (10 linhas)
    # Add produto (15 linhas)
    # Add outro produto (15 linhas)
    # Apply cupom (10 linhas)
    # Calculate shipping (10 linhas)
    # Checkout (20 linhas)
    # Payment (30 linhas)
    # Verify (40 linhas)
    # Cleanup (20 linhas)
    # Total: 220 linhas - MUITO PARA UM TESTE!

# SOLUÇÃO: Dividir em múltiplos testes focados
def test_adicionar_produto_ao_carrinho():
"""Focado: adiciona produto"""
pass

def test_aplicar_cupom_desconto():
"""Focado: aplica cupom"""
pass

def test_calcular_frete():
"""Focado: calcula frete"""
pass

def test_checkout_com_sucesso():
"""Integração: fluxo completo"""
pass


Métricas de Regressão

Dashboard

# Grafana Dashboard - Regression Suite

panels:
- title: "Test Execution Time"
type: graph
queries:
- query: "sum(rate(test_duration_seconds_sum[5m])) / sum(rate(test_duration_seconds_count[5m]))"

- title: "Pass/Fail Rate"
type: piechart
queries:
- query: "sum by (status) (test_results_total)"

- title: "Flaky Tests"
type: stat
queries:
- query: "count(test_flaky == 1)"

- title: "Coverage Trend"
type: timeseries
queries:
- query: "test_coverage_percentage"

KPIs

KPI Target Current Trend
Pass Rate > 95{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} 93{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}
Execution Time < 30 min 35 min
Flaky Rate < 2{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} 3{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}
Coverage > 80{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} 78{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}
Maintenance Effort < 20{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} 25{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}

Conclusão

Testes de regressão são a rede de segurança do seu software. Para uma suite eficaz:

  1. Selecione estrategicamente – Nem tudo precisa de regressão completa
  2. Automatize – Regressão manual não escala
  3. Mantenha – Limpe testes obsoletos regularmente
  4. Monitore – Métricas guiam melhoria
  5. Priorize – Risco e impacto guiam execução


FAQ

P: Quantos testes deve ter na suite de regressão?
R: Depende do projeto. Uma suite saudável cobre funcionalidades críticas com alta cobertura.

P: Como reduzir flaky tests?
R: Use waits explícitos, isole testes, evite dependências, investigue root cause.

P: Testes de regressão devem ser no CI ou separate job?
R: Smokes no CI (bloqueante), regressão completa em job separado (não bloqueante).

P: Como saber se a suite precisa de mais testes?
R: Analise: bugs que passaram, áreas sem cobertura, novos riscos.