Trang chủ
QA Learning Hub
Chương 23 · CI/CD cho QA
Chương 23 Senior

CI/CD Cho QA

Integrate testing vào CI/CD pipeline — GitHub Actions, Jenkins, Docker và automated quality gates để ship với confidence.

🔄 CI/CD Concepts cho QA
  • Continuous Integration (CI)Developer merge code vào main branch thường xuyên (nhiều lần/ngày). Automated tests chạy sau mỗi merge. Fail fast → fix fast. QA benefit: immediate feedback on code quality.
  • Continuous Delivery (CD)Automated pipeline build, test và prepare release. Nhưng deploy lên production cần manual approval. QA có thể vẫn review trước production deploy.
  • Continuous DeploymentTất cả automated — không cần manual approval. Mỗi merge lên main → auto-deploy production nếu all tests pass. Mature teams chỉ. QA phải cực kỳ tin tưởng vào automation coverage.
  • Pipeline StagesThông thường: Build → Unit Tests → Integration Tests → Deploy to Staging → E2E Tests → Security Scan → Manual QA (optional) → Deploy to Production.
  • Fail Fast PrincipleSlow tests last, fast tests first. Unit tests (seconds) → Integration tests (minutes) → E2E tests (hours). Developer gets fast feedback on obvious issues, slower on complex ones.
💡 QA Role trong CI/CD
Senior QA không chỉ "chạy tests trong CI" mà còn: design pipeline stages, define quality gates, choose which tests go where, optimize pipeline speed, và ensure reporting is actionable. QA owns the quality of the pipeline, not just the tests.
🐙 GitHub Actions — Playwright Integration
# .github/workflows/test-pipeline.yml name: QA Test Pipeline on: push: branches: [main, develop] pull_request: branches: [main, develop] env: BASE_URL: ${{ secrets.STAGING_URL }} API_TOKEN: ${{ secrets.QA_API_TOKEN }} jobs: # Job 1: Fast unit/integration tests unit-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '20' } - run: npm ci - run: npm test # unit tests - run: npm run test:api # API integration tests # Job 2: E2E tests (depends on unit-tests passing) e2e-tests: needs: unit-tests # only run if unit tests pass runs-on: ubuntu-latest strategy: matrix: browser: [chromium, firefox] # parallel per browser steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '20' } - run: npm ci - name: Install Playwright run: npx playwright install --with-deps ${{ matrix.browser }} - name: Run E2E tests run: npx playwright test --browser=${{ matrix.browser }} - name: Upload test report uses: actions/upload-artifact@v4 if: always() # upload even on failure with: name: playwright-report-${{ matrix.browser }} path: playwright-report/ # Job 3: Performance tests (scheduled, not on every PR) performance: if: github.ref == 'refs/heads/main' # only on main branch needs: e2e-tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '20' } - run: npm install -g k6 - name: Run load test run: k6 run --out json=results.json tests/performance/load.js - name: Check thresholds run: node scripts/check-performance.js results.json

Secrets Management:

  • Credentials → GitHub Secrets (Settings → Secrets → Actions). Never hardcode in YAML.
  • Environment-specific configs → GitHub Environments (staging, production). Require approval before deploying to production.
  • Rotate secrets regularly. Use least-privilege accounts for CI.
⚙️ Jenkins Pipeline Basics
// Jenkinsfile — Declarative Pipeline pipeline { agent any environment { BASE_URL = credentials('staging-url') SLACK_TOKEN = credentials('slack-token') } stages { stage('Build') { steps { sh 'npm ci' sh 'npm run build' } } stage('Unit Tests') { steps { sh 'npm test -- --reporter=junit' } post { always { junit 'reports/junit.xml' // publish results } } } stage('E2E Tests') { parallel { // run browsers in parallel stage('Chrome') { steps { sh 'npx playwright test --browser=chromium' } } stage('Firefox') { steps { sh 'npx playwright test --browser=firefox' } } } } stage('Deploy to Production') { when { branch 'main' } input { message 'Deploy to production?'; ok 'Deploy' } // manual approval steps { sh './deploy.sh production' } } } post { failure { slackSend channel: '#qa-alerts', message: "Pipeline FAILED: ${env.JOB_NAME} #${env.BUILD_NUMBER}" } } }
🐳 Docker cho QA

Tại sao QA cần Docker:

  • Consistent test environment — "works on my machine" problem eliminated
  • Spin up test dependencies (DB, message queue) locally
  • Isolation — tests không ảnh hưởng nhau khi chạy parallel
  • CI environment identical to local — no surprises
# docker-compose.test.yml — Test environment version: '3.8' services: app: image: myapp:latest ports: ["3000:3000"] environment: - NODE_ENV=test - DATABASE_URL=postgresql://postgres:password@db:5432/testdb depends_on: [db, redis] db: image: postgres:15 environment: POSTGRES_DB: testdb POSTGRES_USER: postgres POSTGRES_PASSWORD: password redis: image: redis:7-alpine playwright: image: mcr.microsoft.com/playwright:v1.40.0-jammy volumes: - ./tests:/tests - ./playwright-report:/playwright-report environment: - BASE_URL=http://app:3000 command: npx playwright test depends_on: [app]

Basic Docker commands cho QA:

# Start test environment docker-compose -f docker-compose.test.yml up -d # Run tests docker-compose -f docker-compose.test.yml run playwright # View logs docker-compose logs -f app # Cleanup docker-compose -f docker-compose.test.yml down -v
🧩 Integrating Tests vào Pipeline
Test TypeWhere in PipelineTriggerFail Action
Unit TestsStage 1 — earliestEvery commitBlock merge
API/Integration TestsStage 2Every PRBlock merge
Smoke Tests (E2E)Stage 3 — after deployAfter staging deployAlert + revert
Full Regression (E2E)Stage 4Nightly or pre-releaseBlock release
Performance TestsStage 5Pre-release + weeklyInvestigate, may block
Security ScanStage 5 (parallel)Pre-release + weeklySecurity review required
Accessibility ScanStage 3PR (on changed pages)Block merge if Critical
🏆 Pipeline Design Principles

1. Fail fast: Fastest tests first. 2. Parallel where possible: Browsers, test suites, services — run simultaneously. 3. Cache aggressively: npm cache, docker layers, browser binaries. 4. Isolate test data: Each test run uses isolated data — no shared state. 5. Report clearly: Failed test = clear artifact with screenshots/logs, not just "FAILED."

📊 Test Reporting trong CI
  • JUnit XML FormatUniversal test report format. Generated by most frameworks. Parsed by Jenkins (junit step), GitHub Actions (test-reporter), and Azure DevOps. Playwright: reporter: ['junit'].
  • Allure ReportRich HTML reports với screenshots, videos, test steps. Playwright/Jest plugin. Host trên server hoặc serve từ CI artifact. Very readable for stakeholders.
  • GitHub PR CommentsAutomatic comment trên PR với test summary: "✅ 150 tests passed | ❌ 3 failed | Screenshots attached." Shows results without leaving PR context.
  • Slack NotificationsKhi pipeline fails → Slack alert tới #qa-alerts channel với: branch, build number, failing tests, link to report. Fast response time.
  • Test History TrendingTrack pass/fail over time. GitHub Actions: "Test Reporter" action. Jenkins: "Test Results Analyzer" plugin. Identify patterns: does a specific test fail every Monday?
✏️ Bài Tập
📝 Bài Tập: CI/CD Pipeline Design

Design CI/CD pipeline cho một team: 4 devs, 2 QA, 1 PM. Tech stack: React frontend, Node.js API, PostgreSQL DB. Deployment: AWS (staging + production). Current state: manual deployments, no automation.

  1. Sketch (text/table) toàn bộ pipeline stages từ developer push code đến production deployment
  2. Identify 3 quality gates và define criteria cho mỗi gate
  3. Viết GitHub Actions workflow YAML (skeleton, không cần full implementation) cho smoke test stage
  4. Define Slack notification strategy: khi nào notify, channel nào, format message
  5. Estimate: pipeline này mất bao lâu để run từ đầu đến cuối? Optimize để giảm xuống dưới 15 phút.