0Pricing
Linux Command Line & Bash Scripting Mastery · Pelajaran

Menguji Fungsi Unit dengan Bats-core

Susun file pengujian, assertion, serta setup/teardown untuk memverifikasi setiap fungsi Bash.

Menguji Fungsi Unit dengan Bats-core adalah pelajaran Linux Command Line & Bash Scripting Mastery gratis di CoddyKit. Ini adalah pelajaran 1 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Linux Command Line & Bash Scripting Mastery, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Linux Command Line & Bash Scripting Mastery mencakup 4 pelajaran total.

Apa Itu Bats-core dan Mengapa Menggunakannya?

Bats-core (Bash Automated Testing System) adalah kerangka kerja pengujian unit de facto untuk Bash. Bats-core memungkinkan Anda menulis pengujian yang terstruktur dan dapat diulang untuk fungsi serta skrip shell dengan cara yang sama seperti Anda menggunakan JUnit untuk Java atau pytest untuk Python.

  • Setiap pengujian berupa blok @test dengan deskripsi yang mudah dipahami.
  • Pengujian berhasil jika setiap perintah di dalamnya mengembalikan kode keluar 0.
  • Pengujian gagal pada kode keluar bukan nol pertama atau saat suatu penegasan gagal.
  • Output kompatibel dengan TAP, sehingga sistem CI (GitHub Actions, Jenkins, GitLab CI) dapat langsung memahaminya.

Instal melalui manajer paket Anda atau klon repositorinya:

# Install via git (recommended — always latest)
git clone https://github.com/bats-core/bats-core.git
cd bats-core && sudo ./install.sh /usr/local

# Or on macOS with Homebrew
brew install bats-core

# Verify installation
bats --version
# bats 1.x.y

Berkas Pengujian Bats Pertama Anda

Berkas pengujian Bats memiliki ekstensi .bats dan diawali shebang khusus. Komponen utama pembangunnya adalah direktif @test yang diikuti string deskripsi dan blok perintah.

  • Shebang #!/usr/bin/env bats memberi tahu shell cara menjalankan berkas tersebut.
  • Setiap blok @test merupakan kasus pengujian yang berdiri sendiri.
  • Anda dapat menjalankan satu berkas dengan bats my_tests.bats atau seluruh direktori dengan bats test/.

Berikut struktur minimal untuk berkas pengujian Bats:

#!/usr/bin/env bats
# File: test/hello.bats

@test "echo outputs the expected string" {
  result=$(echo "hello world")
  [ "$result" = "hello world" ]
}

@test "false command causes test to fail" {
  # Uncommenting the next line would make this test fail:
  # false
  true
}

Memuat Fungsi yang Diuji dengan 'load'

Dalam proyek nyata, fungsi Bash Anda berada di berkas pustaka, bukan di dalam berkas pengujian itu sendiri. Bats menyediakan pembantu load untuk mengambil berkas eksternal berdasarkan lokasi relatif terhadap direktori berkas pengujian.

  • load '../lib/math.sh' mengambil berkas tersebut sebelum setiap pengujian dijalankan.
  • Setelah dimuat, semua fungsi yang didefinisikan dalam berkas itu tersedia di dalam blok pengujian Anda.
  • Simpan fungsi pustaka di direktori lib/ dan pengujian di direktori test/ agar pemisahannya jelas.

Contoh tata letak proyek dan pengujian yang sesuai:

# Project layout:
# lib/math.sh       <- functions to test
# test/math.bats    <- test file

# lib/math.sh
add() {
  echo $(( $1 + $2 ))
}

divide() {
  if [ "$2" -eq 0 ]; then
    echo "Error: division by zero" >&2
    return 1
  fi
  echo $(( $1 / $2 ))
}

# test/math.bats
#!/usr/bin/env bats

load '../lib/math.sh'

@test "add returns correct sum" {
  result=$(add 3 4)
  [ "$result" = "7" ]
}

Penegasan Inti: run, $status, $output

Perintah run adalah inti pengujian Bats. Alih-alih menjalankan perintah secara langsung, membungkusnya dengan run akan menangkap kode keluar dan outputnya tanpa langsung menyebabkan pengujian gagal.

  • $status — menyimpan kode keluar dari perintah run terakhir.
  • $output — menyimpan gabungan stdout dari perintah run terakhir.
  • $lines — array yang setiap elemennya merupakan satu baris output (${lines[0]}, ${lines[1]}, dan seterusnya).

Dengan demikian, Anda dapat melakukan penegasan pada kasus berhasil maupun gagal:

#!/usr/bin/env bats

load '../lib/math.sh'

@test "divide 10 by 2 returns 5" {
  run divide 10 2
  [ "$status" -eq 0 ]
  [ "$output" = "5" ]
}

@test "divide by zero returns exit code 1" {
  run divide 10 0
  [ "$status" -eq 1 ]
}

@test "divide by zero prints error message" {
  run divide 10 0
  # $output captures stderr too when redirected inside the function
  [[ "$output" == *"division by zero"* ]]
}

Menggunakan bats-assert untuk Penegasan yang Ekspresif

Penegasan bawaan [ ] dapat digunakan, tetapi pesan kegagalannya kurang informatif. Pustaka pembantu bats-assert menyediakan fungsi penegasan yang ekspresif dan menampilkan dengan tepat apa yang salah.

  • assert_success — menegaskan bahwa $status bernilai 0.
  • assert_failure — menegaskan bahwa $status bukan nol.
  • assert_output — menegaskan bahwa $output sama dengan string yang diberikan.
  • assert_output --partial — menegaskan bahwa output berisi substring tersebut.
  • refute_output --partial — menegaskan bahwa output TIDAK berisi substring tersebut.

Instal dengan mengklon bats-core/bats-assert ke dalam folder test/helpers/, lalu muat pustaka tersebut:

#!/usr/bin/env bats

# Load bats-assert (cloned into test/helpers/bats-assert)
load 'helpers/bats-assert/load'
load '../lib/math.sh'

@test "add 5 and 3 gives 8" {
  run add 5 3
  assert_success
  assert_output "8"
}

@test "divide by zero fails with descriptive message" {
  run divide 9 0
  assert_failure
  assert_output --partial "division by zero"
}

@test "add does not output an error" {
  run add 1 1
  refute_output --partial "Error"
}

setup dan teardown: Pengait Siklus Hidup Pengujian

Bats menyediakan dua fungsi khusus — setup dan teardown — yang dijalankan secara otomatis di sekitar setiap pengujian. Gunakan keduanya untuk menyiapkan dan membersihkan keadaan bersama agar setiap pengujian dimulai dengan lingkungan yang diketahui.

  • setup() dijalankan sebelum setiap blok @test.
  • teardown() dijalankan setelah setiap blok @test, bahkan jika pengujian gagal.
  • Penggunaan umum: membuat direktori sementara, menetapkan variabel lingkungan, dan menghapus berkas sementara setelah pengujian.
#!/usr/bin/env bats

load '../lib/fileutils.sh'

setup() {
  # Create a fresh temp directory before every test
  TEST_DIR=$(mktemp -d)
  export TEST_DIR
}

teardown() {
  # Always clean up, even on test failure
  rm -rf "$TEST_DIR"
}

@test "write_file creates a file with correct content" {
  run write_file "$TEST_DIR/hello.txt" "hello world"
  assert_success
  [ -f "$TEST_DIR/hello.txt" ]
  [ "$(cat "$TEST_DIR/hello.txt")" = "hello world" ]
}

@test "write_file fails when directory does not exist" {
  run write_file "/nonexistent/dir/file.txt" "data"
  assert_failure
}

setup_file dan teardown_file: Pengait Tingkat Rangkaian

Terkadang Anda hanya perlu menyiapkan sumber daya yang mahal sekali per berkas — bukan sebelum setiap pengujian. Bats menyediakan setup_file dan teardown_file untuk tujuan ini.

  • setup_file() dijalankan sekali sebelum semua pengujian dalam berkas.
  • teardown_file() dijalankan sekali setelah semua pengujian dalam berkas.
  • Gunakan BATS_FILE_TMPDIR (tersedia secara otomatis) untuk berbagi data antara setup_file dan pengujian Anda — variabel biasa tidak akan bertahan di seluruh subshell.

Kasus penggunaan umum: memulai server tiruan atau membangun berkas biner sekali, lalu menghentikannya di akhir:

#!/usr/bin/env bats

setup_file() {
  # Build the project binary once for all tests in this file
  make build --silent
  export BINARY="$PWD/bin/myapp"
  echo "Binary built: $BINARY"
}

teardown_file() {
  # Remove the binary after all tests complete
  rm -f "$BINARY"
  echo "Cleaned up binary"
}

setup() {
  # Still runs before each individual test
  TEST_TMP=$(mktemp -d)
}

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

@test "myapp --version outputs version string" {
  run "$BINARY" --version
  assert_output --partial "1.0"
}

Menguji Fungsi yang Mengubah Berkas

Pola yang sangat umum adalah menguji fungsi Bash yang membaca dari atau menulis ke sistem berkas. Teknik utamanya adalah menggunakan direktori sementara (melalui mktemp -d di dalam setup) agar pengujian tidak pernah menyentuh berkas nyata dan tidak pernah saling mengganggu.

  • Selalu bekerja di dalam $TEST_DIR (atau $BATS_TEST_TMPDIR — tersedia secara otomatis pada Bats versi terbaru).
  • Gunakan pustaka pembantu bats-file untuk penegasan berkas yang rapi seperti assert_file_exists dan assert_file_contains.
  • Jangan pernah menulis jalur secara langsung seperti /tmp/myfile — pelaksanaan pengujian secara paralel akan saling berbenturan.
#!/usr/bin/env bats

load 'helpers/bats-assert/load'
load 'helpers/bats-file/load'
load '../lib/fileutils.sh'

setup() {
  TEST_DIR="$BATS_TEST_TMPDIR"
}

# lib/fileutils.sh defines:
# append_line() { echo "$2" >> "$1"; }

@test "append_line adds a line to an existing file" {
  echo "first line" > "$TEST_DIR/log.txt"

  run append_line "$TEST_DIR/log.txt" "second line"
  assert_success

  assert_file_contains "$TEST_DIR/log.txt" "second line"
}

@test "append_line creates file if it does not exist" {
  run append_line "$TEST_DIR/new.txt" "hello"
  assert_success
  assert_file_exists "$TEST_DIR/new.txt"
}

Menirukan Perintah Eksternal

Fungsi sering memanggil program eksternal seperti curl, aws, atau git. Dalam pengujian unit, Anda ingin menguji logika Anda, bukan perintah eksternal yang sebenarnya. Teknik peniruan Bats yang paling rapi adalah mendefinisikan fungsi shell dengan nama yang sama seperti perintah tersebut di dalam setup — fungsi itu akan diprioritaskan daripada berkas biner yang sebenarnya.

  • Definisikan fungsi seperti curl() { echo 'mocked response'; return 0; } di dalam setup, lalu ekspor fungsi tersebut.
  • Gunakan export -f curl agar fungsi terlihat di subshell yang dibuat oleh run.
  • Anda juga dapat menulis tiruan ke berkas sementara di PATH untuk skenario yang lebih kompleks.
#!/usr/bin/env bats

load 'helpers/bats-assert/load'
load '../lib/network.sh'

# lib/network.sh defines:
# fetch_status() {
#   local url="$1"
#   local code
#   code=$(curl -s -o /dev/null -w "%{http_code}" "$url")
#   echo "$code"
# }

setup() {
  # Override 'curl' with a mock function
  curl() {
    # Simulate a 200 OK response
    echo "200"
    return 0
  }
  export -f curl
}

@test "fetch_status returns 200 when curl reports 200" {
  run fetch_status "https://example.com"
  assert_success
  assert_output "200"
}

Melewati Pengujian dan Pemberian Tag

Tidak semua pengujian selalu dapat dijalankan — terkadang Anda memerlukan koneksi jaringan nyata, alat tertentu, atau OS tertentu. Bats menyediakan skip untuk melewati pengujian secara kondisional dengan pesan informatif, alih-alih mengomentarinya atau membuat rangkaian pengujian gagal.

  • Panggil skip "reason" di mana saja di dalam blok @test untuk melewati pengujian tersebut.
  • Pengujian yang dilewati muncul sebagai S dalam output dan tidak dihitung sebagai kegagalan.
  • Bats 1.5+ mendukung tag: beri anotasi pada pengujian dengan # bats test_tags=slow,network dan saring dengan bats --filter-tags network test/.
#!/usr/bin/env bats

# bats test_tags=network
@test "API returns valid JSON" {
  # Skip if no internet connectivity
  if ! ping -c1 -W1 8.8.8.8 &>/dev/null; then
    skip "No network connection available"
  fi

  run curl -s "https://api.example.com/health"
  assert_success
  assert_output --partial '"status"'
}

# bats test_tags=unit
@test "slug function lowercases and replaces spaces" {
  # Always runs — pure function, no external deps
  slug() { echo "$1" | tr '[:upper:]' '[:lower:]' | tr ' ' '-'; }
  run slug "Hello World"
  assert_output "hello-world"
}

# Run only unit tests:
# bats --filter-tags unit test/

Menyusun Rangkaian Pengujian Lengkap

Proyek Bats yang tertata baik mengikuti tata letak direktori yang mudah diprediksi, sehingga kontributor baru dapat mulai berkontribusi dengan mudah dan integrasi dengan alur CI menjadi sederhana.

Struktur yang disarankan:

  • lib/ — fungsi Bash produksi (satu berkas untuk setiap fungsi: math.sh, fileutils.sh).
  • test/ — satu berkas .bats untuk setiap berkas pustaka (math.bats, fileutils.bats).
  • test/helpers/ — bats-assert, bats-file, dan bats-support sebagai submodul git.
  • Makefile — target test agar kontributor cukup menjalankan make test.

Jalankan seluruh rangkaian dengan satu perintah:

# Makefile
.PHONY: test
test:
	bats test/

# Run all tests recursively (Bats 1.5+)
# bats --recursive test/

# Run a specific file
# bats test/math.bats

# Run with verbose (TAP) output for CI
# bats --tap test/

# Example directory tree:
# .
# |-- lib/
# |   |-- math.sh
# |   `-- fileutils.sh
# |-- test/
# |   |-- helpers/
# |   |   |-- bats-assert/
# |   |   `-- bats-file/
# |   |-- math.bats
# |   `-- fileutils.bats
# `-- Makefile

Uji Pemahaman: Penegasan Bats-core

Uji pemahaman Anda tentang mekanisme inti pengujian Bats-core.

Ringkasan: Pengujian Unit Bash dengan Bats-core

Dalam pelajaran ini, Anda telah mempelajari cara menyusun dan menulis pengujian unit untuk setiap fungsi Bash menggunakan Bats-core. Berikut poin-poin utamanya:

  • Struktur berkas pengujian — gunakan shebang #!/usr/bin/env bats dan blok @test dengan nama yang deskriptif.
  • load — ambil berkas pustaka Anda agar fungsi tersedia dalam pengujian tanpa menyalin dan menempelkan kode.
  • run + $status + $output — trio inti; selalu gunakan run untuk menangkap hasil tanpa langsung menyebabkan pengujian gagal.
  • bats-assert — pilih assert_success, assert_failure, dan assert_output daripada [ ] mentah agar pesan kegagalan mudah dipahami.
  • setup / teardown — dijalankan sebelum/setelah setiap pengujian; setup_file / teardown_file dijalankan sekali per berkas.
  • Peniruan — sembunyikan perintah eksternal dengan fungsi shell bernama sama yang diekspor menggunakan export -f.
  • skip — lewati secara kondisional pengujian yang bergantung pada sumber daya yang tidak tersedia.
  • Tata letak proyek — pisahkan lib/, test/, dan test/helpers/ agar mudah dipelihara dan diintegrasikan dengan CI.

Pola-pola ini memberi proyek Bash Anda disiplin pengujian yang sama seperti yang akan Anda terapkan pada proyek perangkat lunak modern mana pun.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Menguji Fungsi Unit dengan Bats-core” gratis?

Ya — teks lengkap “Menguji Fungsi Unit dengan Bats-core” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Linux Command Line & Bash Scripting Mastery, upgrade ke CoddyKit PRO. Kursus Linux Command Line & Bash Scripting Mastery mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Menguji Fungsi Unit dengan Bats-core”?

Susun file pengujian, assertion, serta setup/teardown untuk memverifikasi setiap fungsi Bash. Kamu berlatih Linux Command Line & Bash Scripting Mastery dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Linux Command Line & Bash Scripting Mastery?

Tidak diperlukan pengalaman sebelumnya. Linux Command Line & Bash Scripting Mastery di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 1 dari 4.

Berapa lama pelajaran “Menguji Fungsi Unit dengan Bats-core” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Linux Command Line & Bash Scripting Mastery ini?

Ya. Setiap pelajaran Linux Command Line & Bash Scripting Mastery menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Menguji Fungsi Unit dengan Bats-core
  2. Membuat Mock Perintah dan Stub Alat Eksternal
  3. Fixture, Environment Sementara, dan Cakupan
  4. Menjalankan Pengujian Shell dalam Pipeline CI
← Kembali ke Linux Command Line & Bash Scripting Mastery