Testing Shell Script dengan Bats di Linux untuk Otomasi Production

Last updated on


Target keyword: testing shell script linux
Monthly keyword cluster: linux shell scripting, bash scripting linux, testing shell script, otomasi linux production, bash best practice
Weekly intent rotation: Problem-solving + implementation playbook (MOFU/BOFU)

Kalau kamu pernah bilang, “script ini kan simpel, ngapain dites?”, lalu seminggu kemudian cron job gagal karena edge case kecil… kamu nggak sendirian.

Di banyak tim, shell script tumbuh dari satu file kecil jadi tulang punggung otomasi: backup, sinkronisasi, deploy, cleanup, sampai health check. Masalahnya, begitu script makin sering dipakai, bug kecil jadi mahal. Salah parse argumen bisa hapus file yang salah. Exit code yang kebalik bisa bikin pipeline lanjut padahal sebenarnya gagal.

Nah, di sinilah testing shell script linux jadi penting. Artikel ini bahas cara praktis ngetes shell script pakai Bats (Bash Automated Testing System) dengan gaya yang realistis buat production: gampang dijalankan di lokal, bisa dimasukin CI, dan tetap enak di-maintain.

Kenapa testing shell script wajib (bukan “nice to have”)

Banyak orang nyaman ngetes script secara manual:

  • jalankan script,
  • lihat output,
  • kalau kelihatan benar, dianggap selesai.

Pendekatan ini oke buat eksperimen cepat, tapi rapuh untuk otomasi rutin. Ada beberapa risiko:

  1. Regresi diam-diam
    Perubahan kecil di fungsi A bisa ngerusak fungsi B, tapi nggak kelihatan sampai job jalan tengah malam.

  2. Perilaku berbeda antar environment
    Lokalmu aman, tapi di server PATH beda, locale beda, atau dependensi beda versi.

  3. Refactor jadi menakutkan
    Tanpa test, setiap perapihan kode terasa berjudi.

Dengan test otomatis, kamu punya “jaring pengaman”. Perubahan jadi lebih percaya diri dan debugging lebih cepat karena gagal di titik yang jelas.

Kalau kamu belum setup fondasi script yang aman, baca juga:

Kenalan cepat: apa itu Bats?

Bats adalah framework test untuk Bash/shell script. Konsepnya mirip unit test di bahasa lain:

  • kamu bikin file test,
  • tiap @test ngecek satu perilaku,
  • jalankan semuanya sekaligus,
  • dapat hasil pass/fail yang jelas.

Contoh minimal:

@test "penjumlahan sederhana" {
  result=$((2 + 3))
  [ "$result" -eq 5 ]
}

Simple, tapi ini cukup untuk membangun kebiasaan test-first atau minimal test-before-merge pada workflow bash scripting linux.

Setup Bats di Linux

Ada beberapa cara install. Pilih yang paling cocok dengan environment kamu.

Opsi A: install via package manager (jika tersedia)

# Ubuntu/Debian (nama paket bisa berbeda tergantung versi)
sudo apt update
sudo apt install -y bats

Opsi B: clone repo Bats (lebih konsisten antar distro)

git clone https://github.com/bats-core/bats-core.git
cd bats-core
sudo ./install.sh /usr/local

Cek instalasi:

bats -v

Kalau versi tampil, berarti siap lanjut.

Struktur project yang rapi buat testing

Supaya enak dipelihara, hindari campur semua hal di satu file raksasa. Minimal pakai struktur ini:

project/
  scripts/
    backup.sh
    lib.sh
  test/
    backup.bats
  fixtures/
    sample-data/

Tips penting:

  • pindahkan logic reusable ke lib.sh (fungsi-fungsi kecil),
  • backup.sh fokus orkestrasi,
  • fixtures/ isi data dummy untuk test yang repeatable.

Struktur ini bikin script lebih mudah diuji dan cocok buat tim kecil yang jalan cepat.

Contoh script yang akan kita tes

Misal kita punya script sederhana buat validasi file input sebelum diproses.

#!/usr/bin/env bash
set -euo pipefail

validate_input_file() {
  local file="$1"

  if [[ -z "$file" ]]; then
    echo "error: file path required" >&2
    return 2
  fi

  if [[ ! -f "$file" ]]; then
    echo "error: file not found: $file" >&2
    return 3
  fi

  if [[ ! -s "$file" ]]; then
    echo "error: file is empty: $file" >&2
    return 4
  fi

  echo "ok: input valid"
}

Simpan misalnya di scripts/lib.sh.

Sekarang kita buat test/backup.bats:

#!/usr/bin/env bats

setup() {
  TMP_DIR="$(mktemp -d)"
  source "${BATS_TEST_DIRNAME}/../scripts/lib.sh"
}

teardown() {
  rm -rf "$TMP_DIR"
}

@test "gagal saat argumen file kosong" {
  run validate_input_file ""
  [ "$status" -eq 2 ]
  [[ "$output" == *"file path required"* ]]
}

@test "gagal saat file tidak ditemukan" {
  run validate_input_file "$TMP_DIR/not-found.txt"
  [ "$status" -eq 3 ]
  [[ "$output" == *"file not found"* ]]
}

@test "gagal saat file kosong" {
  touch "$TMP_DIR/empty.txt"
  run validate_input_file "$TMP_DIR/empty.txt"
  [ "$status" -eq 4 ]
  [[ "$output" == *"file is empty"* ]]
}

@test "sukses saat file valid" {
  echo "hello" > "$TMP_DIR/input.txt"
  run validate_input_file "$TMP_DIR/input.txt"
  [ "$status" -eq 0 ]
  [[ "$output" == *"ok: input valid"* ]]
}

Jalankan:

bats test/backup.bats

Kalau semua hijau, kamu baru saja punya safety net untuk fungsi kritis.

Pola test yang paling berguna untuk shell script production

Biar test kamu benar-benar kepakai, fokus ke 4 kategori ini:

1) Test exit code

Di dunia CLI/otomasi, exit code itu kontrak. Banyak pipeline bergantung ke sini.

  • sukses harus 0,
  • error spesifik sebaiknya beda kode (misal 2, 3, 4).

2) Test output error yang actionable

Jangan cuma “failed”. Pastikan pesan error bantu user/dev ngerti masalah dan langkah berikutnya.

3) Test edge case input

Contoh:

  • path kosong,
  • file dengan spasi,
  • file sangat kecil/empty,
  • karakter khusus.

4) Test idempotensi untuk operasi aman

Kalau script boleh dijalankan berulang, pastikan run ke-2 tidak merusak state.

Untuk ini kamu bisa kombinasikan dengan panduan:

Integrasi ke CI biar nggak lupa jalanin test

Test yang bagus tapi nggak pernah dijalankan = dekorasi.

Minimal, pasang langkah ini di pipeline CI:

# contoh step CI sederhana
bash -n scripts/*.sh
bats test/*.bats
  • bash -n buat syntax check cepat,
  • bats buat verifikasi perilaku.

Kalau mau lebih matang, bisa tambah:

  • shellcheck untuk static analysis,
  • matrix test untuk beberapa versi Bash.

Dengan ini, setiap PR otomatis dicek sebelum merge.

Strategi adopsi Bats bertahap (biar tim nggak kaget)

Salah satu alasan testing shell script sering ketunda adalah rasa “kebanyakan kerjaan”. Cara paling aman adalah adopsi bertahap, bukan revolusi total.

Minggu 1: pilih 1 script paling kritis (misalnya backup atau cleanup). Tambahkan test untuk 2 jalur sukses dan 2 jalur gagal. Fokus dulu ke exit code + pesan error.

Minggu 2: masukkan test ke CI dan jadikan notifikasi fail terlihat di channel tim. Jangan langsung block merge kalau tim belum siap; pakai mode observasi dulu 3–7 hari.

Minggu 3: mulai wajibkan test untuk script baru. Untuk script lama, gunakan aturan “boy scout”: setiap kali file disentuh, tambah minimal satu test.

Minggu 4 dan seterusnya: review coverage berbasis risiko, bukan jumlah test. Script yang menyentuh data produksi, proses deploy, atau credential harus punya perlindungan lebih ketat.

Dengan ritme ini, tim tetap bisa delivery cepat sambil naikin reliability secara konsisten. Nggak drama, tapi hasilnya kerasa.

Troubleshooting umum saat mulai pakai Bats

Masalah 1: source file gagal di test

Biasanya path salah karena asumsi working directory. Gunakan:

"${BATS_TEST_DIRNAME}/../scripts/lib.sh"

Jangan hardcode path relatif ke direktori tempat kamu menjalankan command.

Masalah 2: test flaky (kadang pass kadang gagal)

Penyebab umum:

  • pakai file temp global yang bentrok,
  • tergantung waktu/network tanpa mock,
  • ada state dari test sebelumnya.

Solusi:

  • selalu pakai mktemp -d di setup,
  • bersihin state di teardown,
  • pisahkan test pure logic dari test integrasi.

Masalah 3: susah ngetes fungsi yang langsung exit

Refactor fungsi supaya return kode, lalu exit dilakukan di layer eksekusi utama. Ini bikin fungsi lebih testable.

Masalah 4: script terlalu besar dan sulit diuji

Pecah jadi:

  • file library berisi fungsi,
  • file runner/entrypoint untuk parsing argumen dan alur utama.

Ini bukan cuma soal test—ini juga ningkatin maintainability.

Checklist implementasi cepat (biar langsung jalan)

  • Instal Bats di environment dev/CI
  • Pisahkan logic fungsi ke file library (lib.sh)
  • Buat test untuk jalur sukses + jalur gagal utama
  • Verifikasi exit code dan pesan error
  • Tambah test edge case input
  • Integrasikan bats ke pipeline CI
  • Jadikan test wajib sebelum merge

Kalau butuh observability lebih lanjut setelah testing, lanjut ke:

FAQ

1) Apakah Bats cocok untuk tim kecil atau solo developer?

Cocok banget. Setup-nya ringan, sintaksnya mudah, dan dampaknya besar untuk mencegah bug berulang di otomasi harian.

2) Wajib pakai Bats-core terbaru?

Disarankan, karena lebih aktif dan dokumentasinya jelas. Tapi prinsip testing-nya tetap sama: cek exit code, output, dan edge case penting.

3) Apakah semua shell script harus di-unit-test?

Nggak harus 100%. Prioritaskan script yang sering jalan, berdampak ke data, atau terhubung ke proses deploy/backup/security.

4) Bedanya test manual vs Bats apa?

Manual cepat untuk eksplorasi, Bats unggul untuk konsistensi. Bats memastikan perilaku tetap benar setiap ada perubahan kode.

Penutup

Di ekosistem otomasi linux production, shell script sering jadi komponen kritis tapi paling kurang dilindungi. Mulai dari test sederhana pakai Bats bisa langsung ningkatin keandalan pipeline kamu tanpa nambah kompleksitas berlebihan.

Kalau mau langkah paling pragmatis: pilih satu script yang paling sering bikin insiden, tulis 4–6 test inti, lalu pasang di CI. Dari situ, kamu bakal ngerasain sendiri efeknya: refactor lebih pede, bug lebih cepat ketahuan, dan jam tidur lebih aman 😄.

Komentar

Real-time

Memuat komentar...

Tulis Komentar

Email tidak akan ditampilkan

0/2000 karakter

Catatan: Komentar akan dimoderasi sebelum ditampilkan. Mohon bersikap sopan dan konstruktif.