# Continuous Testing: Automação Total no Pipeline

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

---

## O Que É Continuous Testing?

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.

### Princípios

1. **Automação completa** - Sem intervenção manual
2. **Feedback rápido** - Resultados em minutos
3. **Shift-Left** - Testar mais cedo
4. **Quality Gates** - Critérios para avançar
5. **Cobertura ampla** - Múltiplos tipos de teste

---

## Pipeline de Continuous Testing

```
Code → Commit → Build → Unit Tests → Integration → E2E → Security → Deploy
          ↓        ↓        ↓           ↓            ↓       ↓        ↓
      Pre-commit Hook   Coverage    Contract     Playwright  SAST     Staging
                       Gate        Tests        Tests     DAST
```

---

## Quality Gates

### Definição

```yaml
# Quality Gates Configuration
quality_gates:
  - name: "Code Coverage"
    type: coverage
    minimum: 80  # %
    blocking: true
    
  - name: "Security Scan"
    type: security
    max_critical: 0
    max_high: 0
    blocking: true
    
  - name: "Test Pass Rate"
    type: test
    minimum: 95  # %
    blocking: true
    
  - name: "Performance"
    type: performance
    max_p95_ms: 500
    blocking: false
    
  - name: "Code Review"
    type: approval
    required_approvals: 1
    blocking: true
```

### Implementação

```bash
#!/bin/bash
# quality-gate.sh

check_coverage() {
    COVERAGE=$(cat coverage.xml | grep -oP 'line-covered="\K[0-9]+')
    TOTAL=$(cat coverage.xml | grep -oP 'line-count="\K[0-9]+')
    PERCENTAGE=$((COVERAGE * 100 / TOTAL))
    
    if [ $PERCENTAGE -lt 80 ]; then
        echo "❌ Coverage $PERCENTAGE% below threshold (80%)"
        return 1
    fi
    echo "✅ Coverage $PERCENTAGE%"
    return 0
}

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

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

# Run all gates
check_coverage && check_security && check_tests
exit $?
```

---

## Shift-Left Testing

### Traditional vs Shift-Left

```
TRADITIONAL:
Requirements → Design → Development → Testing → Production
                          ↓
                    (Late discovery of bugs)

SHIFT-LEFT:
Requirements → Testing → Development → Testing → Production
     ↓
(Early discovery of bugs)
```

### Implementação

```yaml
# .github/workflows/shift-left.yml
name: Shift-Left Pipeline

on: [push, pull_request]

jobs:
  # Stage 1: Pre-commit (Developer Machine)
  pre-commit-checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Pre-commit hooks
        run: |
          pip install pre-commit
          pre-commit run --all-files
      
  # Stage 2: Build
  build:
    needs: pre-commit-checks
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build
        run: docker build -t app:${{ github.sha }} .
  
  # Stage 3: Unit Tests (Fast)
  unit-tests:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: pytest tests/unit -v --cov
  
  # Stage 4: Security (SAST)
  security-sast:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: SonarCloud
        uses: SonarSource/sonarcloud-github-action@master
      
      - name: Semgrep
        uses: returntocorp/semgrep-action@v1
  
  # Stage 5: Integration Tests
  integration-tests:
    needs: [unit-tests, security-sast]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run integration tests
        run: pytest tests/integration -v
  
  # Stage 6: E2E Tests
  e2e-tests:
    needs: integration-tests
    runs-on: ubuntu-latest
    if: github.event_name == 'push'
    steps:
      - uses: actions/checkout@v4
      - name: Playwright tests
        run: npx playwright test
  
  # Stage 7: Deploy to Staging
  deploy-staging:
    needs: e2e-tests
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - deploy to staging
```

---

## Test Selection Strategy

```python
# test_selector.py
import subprocess
from typing import List

class TestSelector:
    def __init__(self, changed_files):
        self.changed_files = changed_files
    
    def select_tests(self) -> List[str]:
        tests = set()
        
        # Unit tests (always run)
        tests.update(self.get_unit_tests())
        
        # Integration tests (based on changes)
        tests.update(self.get_integration_tests())
        
        # E2E tests (only for critical paths or major changes)
        if self.has_critical_changes():
            tests.update(self.get_critical_e2e_tests())
        
        return list(tests)
    
    def get_unit_tests(self):
        # All unit tests
        return self.get_tests_matching("tests/unit/**/*.py")
    
    def get_integration_tests(self):
        tests = set()
        for file in self.changed_files:
            if "database" in file:
                tests.add("tests/integration/test_database.py")
            if "api" in file or "service" in file:
                tests.add("tests/integration/test_api.py")
        return tests
    
    def has_critical_changes(self):
        critical_patterns = ["checkout", "payment", "auth", "core"]
        return any(
            any(p in f for p in critical_patterns) 
            for f in self.changed_files
        )
    
    def get_critical_e2e_tests(self):
        return [
            "tests/e2e/test_checkout.py",
            "tests/e2e/test_login.py",
            "tests/e2e/test_payment.py"
        ]
```

---

## Feedback Loop

```yaml
# Slack notification
- name: Notify on Failure
  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": "*Build Failed* :x:\n${GITHUB_REPOSITORY}\n${GITHUB_RUN_URL}"
          }
        }]
      }
```

---

## Métricas de Continuous Testing

```python
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": "% de testes automatizados",
            "current": "85%",
            "target": "90%"
        },
        "quality_gate_pass_rate": {
            "description": "% de builds passando em quality gates",
            "current": "92%",
            "target": "95%"
        },
        "defect_leakage_rate": {
            "description": "% de defeitos encontrados em produção",
            "current": "8%",
            "target": "<5%"
        }
    }
```

---

## Conclusão

Continuous Testing é essencial para DevOps. As chaves são:

1. **Automação total** - Sem intervenção manual
2. **Feedback rápido** - Minutos, não horas
3. **Quality gates** - Critérios claros
4. **Shift-Left** - Testar o mais cedo possível
5. **Seleção inteligente** - Não rodar tudo sempre
