Testing Strategy

Testing Strategy #

Testing Ansible berbeda dari testing aplikasi. Kamu tidak sedang menguji fungsi yang deterministik — kamu menguji efek samping pada sistem nyata. Apakah nginx benar-benar terinstal? Apakah konfigurasi yang dihasilkan valid? Apakah service berjalan setelah role dieksekusi? Ini membutuhkan pendekatan yang berbeda: lingkungan yang bisa dibuat dan dihancurkan, assertions terhadap state sistem, dan strategi untuk menjaga test suite tetap berguna tanpa menjadi beban yang lebih berat dari manfaatnya.

Piramida Testing untuk Ansible #

          ╔════════════════╗
          ║  Integration   ║  ← Sedikit, mahal, paling mendekati production
          ╠════════════════╣
          ║    Molecule    ║  ← Per role, test di container
          ╠════════════════╣
          ║  Syntax Check  ║  ← Per playbook/role
          ╠════════════════╣
          ║  ansible-lint  ║  ← Per commit, paling cepat
          ╚════════════════╝
               Banyak, murah

Investasi terbesar ada di base — linting dan syntax check yang cepat memberikan umpan balik paling cepat dengan biaya paling rendah.


Layer 1: Lint dan Syntax Check (Detik) #

# Jalankan di pre-commit hook dan di setiap PR
ansible-lint --profile production

# Syntax check semua playbook
for playbook in playbooks/*.yml; do
  ansible-playbook "$playbook" --syntax-check -i inventory/staging/
done

# Check mode: simulasikan perubahan tanpa menerapkannya
ansible-playbook -i inventory/staging/ site.yml --check --diff

Ini harus berjalan dalam hitungan detik dan menjadi gate pertama sebelum kode bisa masuk ke repository.


Layer 2: Molecule Test (Menit) #

Setiap role harus punya Molecule scenario. Fokus test pada efek yang dapat diverifikasi:

# roles/postgresql/molecule/default/verify.yml
---
- name: Verify PostgreSQL installation
  hosts: all
  gather_facts: false

  tasks:
    - name: Verifikasi postgresql terinstal
      command: psql --version
      register: psql_version
      changed_when: false
      failed_when: psql_version.rc != 0

    - name: Verifikasi service aktif dan enabled
      systemd:
        name: postgresql
      register: pg_service
      failed_when:
        - pg_service.status.ActiveState != 'active'
        - pg_service.status.UnitFileState != 'enabled'

    - name: Verifikasi port 5432 terbuka
      wait_for:
        port: 5432
        timeout: 10
        state: started

    - name: Verifikasi koneksi database berhasil
      command: >
        psql -U postgres -c "SELECT version();"        
      become: true
      become_user: postgres
      register: pg_connect
      changed_when: false

    - name: Verifikasi konfigurasi yang dihasilkan valid
      command: pg_lsclusters
      register: clusters
      changed_when: false
      failed_when: "'online' not in clusters.stdout"

    - name: Verifikasi listen_addresses sesuai konfigurasi
      command: >
        psql -U postgres -c "SHOW listen_addresses;"        
      become: true
      become_user: postgres
      register: listen_addr
      changed_when: false
      failed_when: postgresql_listen_addresses not in listen_addr.stdout

Pola Test yang Efisien: Idempotency Check #

Molecule secara otomatis menjalankan converge dua kali untuk mengecek idempotency. Pastikan semua task mengembalikan ok di run kedua:

# molecule/default/molecule.yml
provisioner:
  name: ansible
  config_options:
    defaults:
      callbacks_enabled: profile_tasks  # Lihat task mana yang tidak idempoten

verifier:
  name: ansible
  enabled: true

# Sequence default Molecule sudah melakukan idempotency check:
# create → converge → idempotency (converge lagi, pastikan 0 changed) → verify → destroy

Jika ada task yang selalu changed di run kedua, itu adalah bug idempotency yang harus diperbaiki.


Layer 3: Integration Test (Menit ke Puluhan Menit) #

Integration test memverifikasi bahwa beberapa role bekerja bersama dengan benar:

# tests/integration/test-stack.yml
---
- name: Integration test: full stack
  hosts: test_servers
  become: true

  roles:
    - common
    - nginx
    - myapp

  post_tasks:
    - name: Tunggu stack siap
      pause:
        seconds: 15

    - name: Verifikasi halaman utama dapat diakses
      uri:
        url: "http://localhost:{{ nginx_http_port }}"
        status_code: 200
        return_content: true
      register: homepage
      failed_when: "'Welcome' not in homepage.content"

    - name: Verifikasi API endpoint
      uri:
        url: "http://localhost:{{ nginx_http_port }}/api/health"
        status_code: 200

    - name: Verifikasi log aplikasi tidak ada error
      shell: "grep -c ERROR /var/log/myapp/app.log || true"
      register: error_count
      changed_when: false
      failed_when: error_count.stdout | int > 0

Strategi untuk Test Environment #

# Opsi 1: Docker (cepat, tapi tidak 100% mirip production)
# Cocok untuk: unit test role, idempotency check
driver:
  name: docker

platforms:
  - name: ubuntu22
    image: geerlingguy/docker-ubuntu2204-ansible:latest
    pre_build_image: true

# Opsi 2: Vagrant (lebih mirip VM nyata, lebih lambat)
# Cocok untuk: integration test yang butuh kernel features
driver:
  name: vagrant

platforms:
  - name: ubuntu22
    box: ubuntu/jammy64
    memory: 1024

# Opsi 3: EC2/cloud instance (paling akurat, paling mahal)
# Gunakan hanya untuk test sebelum major release
driver:
  name: ec2

platforms:
  - name: ubuntu22
    image: ami-xxxxx
    instance_type: t3.micro

Apa yang TIDAK Perlu Di-Test #

Testing yang berlebihan menciptakan beban maintenance tanpa nilai proporsional:

TIDAK perlu di-test:
  ✗ Apakah modul apt bekerja — itu tanggung jawab Ansible, bukan kita
  ✗ Apakah variabel dengan nilai default menggunakan nilai defaultnya
  ✗ Setiap baris konfigurasi yang dihasilkan template
  ✗ Behavior yang sudah ditest oleh Molecule idempotency check

PERLU di-test:
  ✓ Apakah service berjalan dan dapat menerima koneksi
  ✓ Apakah konfigurasi yang dihasilkan valid secara sintaks
  ✓ Apakah role idempoten (Molecule handle ini otomatis)
  ✓ Apakah kombinasi role bekerja bersama (integration test)
  ✓ Edge case: apa yang terjadi jika role dijalankan di server yang sudah ada datanya

Ringkasan #

  • Piramida testing: banyak lint/syntax check (detik) → beberapa Molecule test per role (menit) → sedikit integration test (puluhan menit). Jangan balik piramida ini.
  • Molecule secara otomatis melakukan idempotency check (converge dua kali) — pastikan semua task mengembalikan ok di run kedua, bukan changed.
  • Test yang baik memverifikasi efek yang bisa diobservasi: service berjalan, port terbuka, koneksi berhasil — bukan implementasi internal.
  • Jangan test behavior Ansible — fokus test pada behavior sistem yang dihasilkan oleh role, bukan pada cara Ansible mencapainya.
  • Test environment dengan Docker untuk kecepatan (unit test role), Vagrant untuk akurasi (integration test), cloud instance untuk validasi final sebelum major release.
  • Test suite yang tidak di-maintain lebih buruk dari tidak ada test — hapus test yang selalu fail atau tidak pernah menemukan bug daripada membiarkannya menjadi noise.

← Sebelumnya: Code Quality   Berikutnya: Team Workflow →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact