<p><strong>Meta Description:</strong> Aprenda a implementar testes de regressão eficazes: estratégias de seleção, automação, manutenção e como construir uma suite de regressão sustentável.</p>

<hr>
<h2>O Que São Testes de Regressão?</h2>

<p>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.</p>

<h3>Quando Executar Regressão</h3>

<figure class="wp-block-table"><table>
<tr><th>Situação</th><th>Recomendação</th></tr>
<tr><td>Antes de cada release</td><td>Suite completa</td></tr>
<tr><td>Após hotfix</td><td>Smoke + área afetada</td></tr>
<tr><td>Antes de deploy</td><td>Critical path</td></tr>
<tr><td>Semanalmente (CI)</td><td>Suite rápida</td></tr>
<tr><td>Sob demanda</td><td>Após mudanças críticas</td></tr>
</table></figure>

<hr>
<h2>Estratégias de Seleção de Testes</h2>

<h3>1. Regressão Completa</h3>

<p>Executa toda a suite de testes.</p>

<p><strong>Quando usar:</strong><br><ul><li>Releases major</li><ol><li>Mudanças arquiteturais</li><br><li>After database migration</li><br><li>Final gate para produção</li><br></ol><br><h3>2. Regressão Parcial (Seletiva)</h3></p>

<p>Seleciona subconjunto baseado em mudanças.</p>

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

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

<p>tests = set()<br>    for changed_file in changed_files:<br>        module = extract_module(changed_file)<br>        if module in module_to_tests:<br>            tests.update(module_to_tests[module])</p>

<p>return tests</p>

<p># Executar apenas testes afetados<br>affected_tests = get_affected_tests(get_changed_files())<br>pytest.main(affected_tests)<br></code></pre></p>

<h3>3. Regressão Baseada em Risco</h3>

<p>Prioriza por risco de impacto.</p>

<figure class="wp-block-table"><table>
<tr><th>Prioridade</th><th>Critério</th><th>Execução</th></tr>
<tr><td><strong>Crítica</strong></td><td>Fluxos de pagamento, auth</td><td>Sempre</td></tr>
<tr><td><strong>Alta</strong></td><td>Features principais</td><td>Antes de cada release</td></tr>
<tr><td><strong>Média</strong></td><td>Features secundárias</td><td>Semanalmente</td></tr>
<tr><td><strong>Baixa</strong></td><td>Edge cases</td><td>Mensalmente</td></tr>
</table></figure>

<h3>4. Regressão Híbrida</h3>

<p>Combina múltiplas estratégias.</p>

<pre><code># strategy: Hybrid Regression

<p># Nivel 1: Critical (sempre)<ol><li>tests/auth/login*.py</li><br><li>tests/auth/logout*.py</li><br><li>tests/payment/checkout*.py</li><br><li>tests/smoke/*.py</li><br></ol><br># Nivel 2: Based on changes<ol><li>get_affected_tests()</li><br></ol><br># Nivel 3: Risk-based<ol><li>tests/high_risk_features*.py</li><br></ol><br># Nivel 4: Full (releases only)<ol><li>tests/full_suite/*.py</li></ol></ul><br></code></pre></p>

<hr>
<h2>Automação de Regressão</h2>

<h3>Framework Ideal</h3>

<pre><code>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
</code></pre>

<h3>Page Object Pattern</h3>

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

<p>class BasePage:<br>    def __init__(self, driver):<br>        self.driver = driver<br>        self.wait = WebDriverWait(driver, 10)</p>

<p>def click(self, locator):<br>        self.wait.until(EC.element_to_be_clickable(locator)).click()</p>

<p>def send_keys(self, locator, text):<br>        element = self.wait.until(EC.presence_of_element_located(locator))<br>        element.clear()<br>        element.send_keys(text)</p>

<p>def get_text(self, locator):<br>        return self.wait.until(EC.presence_of_element_located(locator)).text</p>

<p>def is_visible(self, locator):<br>        try:<br>            return self.wait.until(<br>                EC.visibility_of_element_located(locator)<br>            ).is_displayed()<br>        except:<br>            return False</p>

<p># pages/login_page.py<br>from selenium.webdriver.common.by import By</p>

<p>class LoginPage(BasePage):<br>    URL = "https://exemplo.com/login"</p>

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

<p>def load(self):<br>        self.driver.get(self.URL)<br>        return self</p>

<p>def login(self, email, password):<br>        self.send_keys(self.EMAIL, email)<br>        self.send_keys(self.PASSWORD, password)<br>        self.click(self.LOGIN_BUTTON)<br>        return self</p>

<p>def get_error(self):<br>        return self.get_text(self.ERROR_MESSAGE)<br></code></pre></p>

<h3>Execução Paralela</h3>

<pre><code># pytest.ini
[pytest]
addopts = -n auto --dist loadscope
# -n auto: usa todas CPUs disponíveis
# --dist loadscope: agrupa testes por scope
</code></pre>

<pre><code># GitHub Actions
name: Regression Tests

<p>on:<br>  schedule:<br>    - cron: '0 6 <em> </em> 1'  # Toda segunda 6h</p>

<p>jobs:<br>  regression:<br>    runs-on: ubuntu-latest<br>    strategy:<br>      matrix:<br>        shard: [1, 2, 3, 4]</p>

<p>steps:<br>      - uses: actions/checkout@v4</p>

<p>- name: Run test shard ${{ matrix.shard }}<br>        run: |<br>          pytest tests/ <br>            --dist loadscope <br>            --maxprocesses 4 <br>            --split=${{ matrix.shard }}/4<br></code></pre></p>

<hr>
<h2>Manutenção da Suite</h2>

<h3>Identificando Testes Obsoletos</h3>

<pre><code># script: identify_obsolete_tests.py
import subprocess
from datetime import datetime

<p>def analyze_test_usage():<br>    """Analisa quais testes não foram executados ou falham sempre"""</p>

<p>results = []</p>

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

<p># 2. Testes que sempre falham<br>    # 3. Testes duplicados<br>    # 4. Cobertura redundante</p>

<p>return results</p>

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

<h3>Indicadores de "Code Smell" em Testes</h3>

<pre><code># 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!

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

<p>def test_aplicar_cupom_desconto():<br>    """Focado: aplica cupom"""<br>    pass</p>

<p>def test_calcular_frete():<br>    """Focado: calcula frete"""<br>    pass</p>

<p>def test_checkout_com_sucesso():<br>    """Integração: fluxo completo"""<br>    pass<br></code></pre></p>

<hr>
<h2>Métricas de Regressão</h2>

<h3>Dashboard</h3>

<pre><code># Grafana Dashboard - Regression Suite

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

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

<p>- title: "Flaky Tests"<br>    type: stat<br>    queries:<br>      - query: "count(test_flaky == 1)"</p>

<p>- title: "Coverage Trend"<br>    type: timeseries<br>    queries:<br>      - query: "test_coverage_percentage"<br></code></pre></p>

<h3>KPIs</h3>

<figure class="wp-block-table"><table>
<tr><th>KPI</th><th>Target</th><th>Current</th><th>Trend</th></tr>
<tr><td>Pass Rate</td><td>&gt; 95{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}</td><td>93{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}</td><td>↑</td></tr>
<tr><td>Execution Time</td><td>&lt; 30 min</td><td>35 min</td><td>↓</td></tr>
<tr><td>Flaky Rate</td><td>&lt; 2{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}</td><td>3{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}</td><td>→</td></tr>
<tr><td>Coverage</td><td>&gt; 80{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}</td><td>78{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}</td><td>↑</td></tr>
<tr><td>Maintenance Effort</td><td>&lt; 20{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}</td><td>25{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}</td><td>↓</td></tr>
</table></figure>

<hr>
<h2>Conclusão</h2>

<p>Testes de regressão são a rede de segurança do seu software. Para uma suite eficaz:<br><ol><li><strong>Selecione estrategicamente</strong> - Nem tudo precisa de regressão completa</li><br><li><strong>Automatize</strong> - Regressão manual não escala</li><br><li><strong>Mantenha</strong> - Limpe testes obsoletos regularmente</li><br><li><strong>Monitore</strong> - Métricas guiam melhoria</li><br><li><strong>Priorize</strong> - Risco e impacto guiam execução</li><br></ol><br><hr><br><h3>FAQ</h3></p>

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

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

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

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