<p><strong>Meta Description:</strong> Aprenda continuous testing: automação completa no pipeline CI/CD, quality gates, shift-left e como implementar testes em cada estágio.</p>

<hr>
<h2>O Que É Continuous Testing?</h2>

<p>Continuous Testing é a prática de executar testes automaticamente em cada mudança de código, proporcionando feedback rápido e contínuo sobre a qualidade do software.</p>

<h3>Princípios</h3>
<ol><li><strong>Automação completa</strong> - Sem intervenção manual</li>
<li><strong>Feedback rápido</strong> - Resultados em minutos</li>
<li><strong>Shift-Left</strong> - Testar mais cedo</li>
<li><strong>Quality Gates</strong> - Critérios para avançar</li>
<li><strong>Cobertura ampla</strong> - Múltiplos tipos de teste</li>
</ol>
<hr>
<h2>Pipeline de Continuous Testing</h2>

<pre><code>Code → Commit → Build → Unit Tests → Integration → E2E → Security → Deploy
          ↓        ↓        ↓           ↓            ↓       ↓        ↓
      Pre-commit Hook   Coverage    Contract     Playwright  SAST     Staging
                       Gate        Tests        Tests     DAST
</code></pre>

<hr>
<h2>Quality Gates</h2>

<h3>Definição</h3>

<pre><code># Quality Gates Configuration
quality_gates:
  - name: "Code Coverage"
    type: coverage
    minimum: 80  # {6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}
    blocking: true

<p>- name: "Security Scan"<br>    type: security<br>    max_critical: 0<br>    max_high: 0<br>    blocking: true</p>

<p>- name: "Test Pass Rate"<br>    type: test<br>    minimum: 95  # {6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}<br>    blocking: true</p>

<p>- name: "Performance"<br>    type: performance<br>    max_p95_ms: 500<br>    blocking: false</p>

<p>- name: "Code Review"<br>    type: approval<br>    required_approvals: 1<br>    blocking: true<br></code></pre></p>

<h3>Implementação</h3>

<pre><code>#!/bin/bash
# quality-gate.sh

<p>check_coverage() {<br>    COVERAGE=$(cat coverage.xml | grep -oP 'line-covered="K[0-9]+')<br>    TOTAL=$(cat coverage.xml | grep -oP 'line-count="K[0-9]+')<br>    PERCENTAGE=$((COVERAGE * 100 / TOTAL))</p>

<p>if [ $PERCENTAGE -lt 80 ]; then<br>        echo "❌ Coverage $PERCENTAGE{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} below threshold (80{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442})"<br>        return 1<br>    fi<br>    echo "✅ Coverage $PERCENTAGE{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}"<br>    return 0<br>}</p>

<p>check_security() {<br>    CRITICAL=$(grep -c "critical" snyk-report.json)<br>    if [ $CRITICAL -gt 0 ]; then<br>        echo "❌ $CRITICAL critical vulnerabilities found"<br>        return 1<br>    fi<br>    echo "✅ No critical vulnerabilities"<br>    return 0<br>}</p>

<p>check_tests() {<br>    PASS_RATE=$(python -c "print($passed / $total * 100)")<br>    if (( $(echo "$PASS_RATE &lt; 95&quot; | bc -l) )); then<br>        echo "❌ Pass rate $PASS_RATE{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} below threshold (95{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442})"<br>        return 1<br>    fi<br>    echo "✅ Pass rate $PASS_RATE{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}"<br>    return 0<br>}</p>

<p># Run all gates<br>check_coverage &amp;&amp; check_security &amp;&amp; check_tests<br>exit $?<br></code></pre></p>

<hr>
<h2>Shift-Left Testing</h2>

<h3>Traditional vs Shift-Left</h3>

<pre><code>TRADITIONAL:
Requirements → Design → Development → Testing → Production
                          ↓
                    (Late discovery of bugs)

<p>SHIFT-LEFT:<br>Requirements → Testing → Development → Testing → Production<br>     ↓<br>(Early discovery of bugs)<br></code></pre></p>

<h3>Implementação</h3>

<pre><code># .github/workflows/shift-left.yml
name: Shift-Left Pipeline

<p>on: [push, pull_request]</p>

<p>jobs:<br>  # Stage 1: Pre-commit (Developer Machine)<br>  pre-commit-checks:<br>    runs-on: ubuntu-latest<br>    steps:<br>      - uses: actions/checkout@v4<br>      - name: Pre-commit hooks<br>        run: |<br>          pip install pre-commit<br>          pre-commit run --all-files</p>

<p># Stage 2: Build<br>  build:<br>    needs: pre-commit-checks<br>    runs-on: ubuntu-latest<br>    steps:<br>      - uses: actions/checkout@v4<br>      - name: Build<br>        run: docker build -t app:${{ github.sha }} .</p>

<p># Stage 3: Unit Tests (Fast)<br>  unit-tests:<br>    needs: build<br>    runs-on: ubuntu-latest<br>    steps:<br>      - run: pytest tests/unit -v --cov</p>

<p># Stage 4: Security (SAST)<br>  security-sast:<br>    needs: build<br>    runs-on: ubuntu-latest<br>    steps:<br>      - uses: actions/checkout@v4<br>      - name: SonarCloud<br>        uses: SonarSource/sonarcloud-github-action@master</p>

<p>- name: Semgrep<br>        uses: returntocorp/semgrep-action@v1</p>

<p># Stage 5: Integration Tests<br>  integration-tests:<br>    needs: [unit-tests, security-sast]<br>    runs-on: ubuntu-latest<br>    steps:<br>      - uses: actions/checkout@v4<br>      - name: Run integration tests<br>        run: pytest tests/integration -v</p>

<p># Stage 6: E2E Tests<br>  e2e-tests:<br>    needs: integration-tests<br>    runs-on: ubuntu-latest<br>    if: github.event_name == 'push'<br>    steps:<br>      - uses: actions/checkout@v4<br>      - name: Playwright tests<br>        run: npx playwright test</p>

<p># Stage 7: Deploy to Staging<br>  deploy-staging:<br>    needs: e2e-tests<br>    runs-on: ubuntu-latest<br>    environment: staging<br>    steps:<br>      - deploy to staging<br></code></pre></p>

<hr>
<h2>Test Selection Strategy</h2>

<pre><code># test_selector.py
import subprocess
from typing import List

<p>class TestSelector:<br>    def __init__(self, changed_files):<br>        self.changed_files = changed_files</p>

<p>def select_tests(self) -&gt; List[str]:<br>        tests = set()</p>

<p># Unit tests (always run)<br>        tests.update(self.get_unit_tests())</p>

<p># Integration tests (based on changes)<br>        tests.update(self.get_integration_tests())</p>

<p># E2E tests (only for critical paths or major changes)<br>        if self.has_critical_changes():<br>            tests.update(self.get_critical_e2e_tests())</p>

<p>return list(tests)</p>

<p>def get_unit_tests(self):<br>        # All unit tests<br>        return self.get_tests_matching("tests/unit/<em>*/</em>.py")</p>

<p>def get_integration_tests(self):<br>        tests = set()<br>        for file in self.changed_files:<br>            if "database" in file:<br>                tests.add("tests/integration/test_database.py")<br>            if "api" in file or "service" in file:<br>                tests.add("tests/integration/test_api.py")<br>        return tests</p>

<p>def has_critical_changes(self):<br>        critical_patterns = ["checkout", "payment", "auth", "core"]<br>        return any(<br>            any(p in f for p in critical_patterns) <br>            for f in self.changed_files<br>        )</p>

<p>def get_critical_e2e_tests(self):<br>        return [<br>            "tests/e2e/test_checkout.py",<br>            "tests/e2e/test_login.py",<br>            "tests/e2e/test_payment.py"<br>        ]<br></code></pre></p>

<hr>
<h2>Feedback Loop</h2>

<pre><code># Slack notification
<ul><li>name: Notify on Failure</li></ul>
  if: failure()
  uses: slackapi/slack-github-action@v1
  with:
    channel-id: 'qa-alerts'
    payload: |
      {
        "text": "❌ Build #${GITHUB_RUN_NUMBER} failed",
        "blocks": [{
          "type": "section",
          "text": {
            "type": "mrkdwn",
            "text": "<em>Build Failed</em> :x:n${GITHUB_REPOSITORY}n${GITHUB_RUN_URL}"
          }
        }]
      }
</code></pre>

<hr>
<h2>Métricas de Continuous Testing</h2>

<pre><code>def continuous_testing_metrics():
    return {
        "test_cycle_time": {
            "description": "Tempo do commit ao deploy",
            "current": "45 min",
            "target": "30 min",
            "trend": "improving"
        },
        "test_automation_rate": {
            "description": "{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} de testes automatizados",
            "current": "85{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}",
            "target": "90{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}"
        },
        "quality_gate_pass_rate": {
            "description": "{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} de builds passando em quality gates",
            "current": "92{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}",
            "target": "95{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}"
        },
        "defect_leakage_rate": {
            "description": "{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} de defeitos encontrados em produção",
            "current": "8{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}",
            "target": "&lt;5{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442}&quot;
        }
    }
</code></pre>

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

<p>Continuous Testing é essencial para DevOps. As chaves são:<br><ol><li><strong>Automação total</strong> - Sem intervenção manual</li><br><li><strong>Feedback rápido</strong> - Minutos, não horas</li><br><li><strong>Quality gates</strong> - Critérios claros</li><br><li><strong>Shift-Left</strong> - Testar o mais cedo possível</li><br><li><strong>Seleção inteligente</strong> - Não rodar tudo sempre</li></ol></p>