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
@testdengan 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.yBerkas 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 batsmemberi tahu shell cara menjalankan berkas tersebut. - Setiap blok
@testmerupakan kasus pengujian yang berdiri sendiri. - Anda dapat menjalankan satu berkas dengan
bats my_tests.batsatau seluruh direktori denganbats 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 direktoritest/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 perintahrunterakhir.$output— menyimpan gabungan stdout dari perintahrunterakhir.$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$statusbernilai 0.assert_failure— menegaskan bahwa$statusbukan nol.assert_output— menegaskan bahwa$outputsama 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 antarasetup_filedan 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-fileuntuk penegasan berkas yang rapi sepertiassert_file_existsdanassert_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 dalamsetup, lalu ekspor fungsi tersebut. - Gunakan
export -f curlagar fungsi terlihat di subshell yang dibuat olehrun. - Anda juga dapat menulis tiruan ke berkas sementara di
PATHuntuk 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@testuntuk melewati pengujian tersebut. - Pengujian yang dilewati muncul sebagai
Sdalam output dan tidak dihitung sebagai kegagalan. - Bats 1.5+ mendukung tag: beri anotasi pada pengujian dengan
# bats test_tags=slow,networkdan saring denganbats --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.batsuntuk setiap berkas pustaka (math.bats,fileutils.bats).test/helpers/— bats-assert, bats-file, dan bats-support sebagai submodul git.Makefile— targettestagar kontributor cukup menjalankanmake 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
# `-- MakefileUji 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 batsdan blok@testdengan nama yang deskriptif. load— ambil berkas pustaka Anda agar fungsi tersedia dalam pengujian tanpa menyalin dan menempelkan kode.run+$status+$output— trio inti; selalu gunakanrununtuk menangkap hasil tanpa langsung menyebabkan pengujian gagal.- bats-assert — pilih
assert_success,assert_failure, danassert_outputdaripada[ ]mentah agar pesan kegagalan mudah dipahami. setup/teardown— dijalankan sebelum/setelah setiap pengujian;setup_file/teardown_filedijalankan 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/, dantest/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
- Menguji Fungsi Unit dengan Bats-core
- Membuat Mock Perintah dan Stub Alat Eksternal
- Fixture, Environment Sementara, dan Cakupan
- Menjalankan Pengujian Shell dalam Pipeline CI