Penguasaan Baris Perintah Linux & Penskripan Bash · Pelajaran

Meniru Perintah dan Menyediakan Alat Luaran Palsu

Gantikan PATH dan takrifkan binari palsu untuk menguji skrip tanpa menyentuh sistem sebenar

Pelajaran 2 daripada 413 langkah

Meniru Perintah dan Menyediakan Alat Luaran Palsu ialah pelajaran Penguasaan Baris Perintah Linux & Penskripan Bash percuma di CoddyKit. Ini ialah pelajaran 2 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Penguasaan Baris Perintah Linux & Penskripan Bash, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Penguasaan Baris Perintah Linux & Penskripan Bash merangkumi sejumlah 4 pelajaran.

Mengapa Membuat Olok-olok Arahan dalam Ujian Bash?

Apabila anda menguji skrip Bash yang memanggil curl, aws, git atau sebarang alat luaran, anda menghadapi masalah: panggilan sebenar mengakses rangkaian, mengubah keadaan, menelan kos atau sekadar gagal dalam persekitaran CI yang tidak memasang alat tersebut.

Olok-olok bermaksud menggantikan arahan sebenar dengan arahan palsu yang anda kawal. Arahan palsu anda (iaitu stub) mengembalikan output dan kod keluar yang boleh dijangka, jadi ujian anda pantas, terasing dan boleh dihasilkan semula.

  • Tiada akses rangkaian atau awan diperlukan
  • Ujian dijalankan dalam milisaat, bukannya saat
  • Anda boleh mensimulasikan ralat yang sukar dicetuskan pada sistem sebenar
  • Saluran paip CI kekal bersih dan bebas kebergantungan

Bash memberikan mekanisme yang sangat mudah untuk melakukan ini: letakkan sahaja binari palsu anda di lokasi yang lebih awal dalam $PATH berbanding binari sebenar.

Cara Carian PATH Berfungsi

Apabila shell melaksanakan arahan seperti curl, ia mencari setiap direktori dalam $PATH dari kiri ke kanan dan menjalankan padanan pertama yang ditemuinya.

Ini bermakna jika anda meletakkan di hadapan satu direktori yang mengandungi skrip curl anda sendiri, shell tidak akan sampai ke /usr/bin/curl.

Corak penggantian:

  1. Cipta direktori sementara (iaitu binari stub anda)
  2. Tulis boleh laku palsu dengan nama yang sama seperti arahan sebenar
  3. Letakkan direktori itu di hadapan PATH
  4. Jalankan skrip yang diuji — ia memanggil stub anda, bukan binari sebenar
  5. Bersihkan direktori sementara selepas ujian

Kaedah ini berfungsi tanpa akses root, tanpa mengubah suai fail sistem dan tanpa rangka kerja khas.

Mencipta Direktori Stub

Corak piawai menggunakan mktemp -d untuk mencipta direktori sementara terpencil bagi stub anda. Setiap ujian atau suit ujian mendapat direktorinya sendiri, sekali gus mengelakkan pencemaran antara ujian.

Selepas ujian selesai, buang direktori tersebut dengan rm -rf. Menggunakan trap memastikan pembersihan berlaku walaupun ujian keluar lebih awal disebabkan oleh ralat.

#!/usr/bin/env bash
# Setup a stub bin directory for testing

# Create the temp dir
STUB_BIN=$(mktemp -d)

# Always clean up on exit (success, error, or signal)
trap 'rm -rf "$STUB_BIN"' EXIT

# Prepend it to PATH so our stubs take priority
export PATH="$STUB_BIN:$PATH"

echo "Stub bin: $STUB_BIN"
echo "PATH starts with: ${PATH%%:*}"

# Your tests would go here...
echo "Tests complete."

Menulis Stub Pertama Anda

Stub hanyalah fail boleh laku yang mempunyai nama sama seperti arahan yang ingin anda gantikan. Stub itu mencetak apa sahaja output yang dijangka oleh skrip yang diuji dan keluar dengan kod yang anda pilih.

Peraturan utama untuk stub:

  • Fail mestilah boleh laku (chmod +x)
  • Baris shebang (#!/usr/bin/env bash) diperlukan
  • Gema output yang akan dihuraikan oleh skrip sebenar anda
  • Gunakan exit 0 untuk kejayaan dan kod bukan sifar untuk kegagalan yang disimulasikan
#!/usr/bin/env bash
# Create a stub for 'curl' that returns a fake HTTP response

STUB_BIN=$(mktemp -d)
trap 'rm -rf "$STUB_BIN"' EXIT
export PATH="$STUB_BIN:$PATH"

# Write the stub
cat > "$STUB_BIN/curl" << 'EOF'
#!/usr/bin/env bash
# Fake curl: always returns a 200 OK with a JSON body
echo '{"status": "ok", "version": "1.2.3"}'
exit 0
EOF
chmod +x "$STUB_BIN/curl"

# Verify the stub is found before the real curl
which curl
curl https://example.com/api/version

Menguji Skrip yang Memanggil curl

Sekarang mari kita gabungkan semuanya. Katakan anda mempunyai skrip penggunaan yang memanggil curl untuk memeriksa titik akhir kesihatan, kemudian keluar dengan ralat jika perkhidmatan itu tidak sihat. Anda mahu menguji laluan berjaya dan laluan gagal tanpa pelayan sebenar.

#!/usr/bin/env bash
# Script under test: check_health.sh
# It calls curl and checks the returned JSON

check_health() {
  local url="$1"
  local response
  response=$(curl -sf "$url")
  if [[ "$response" == *'"healthy":true'* ]]; then
    echo "Service is UP"
    return 0
  else
    echo "Service is DOWN" >&2
    return 1
  fi
}

# ---- Test harness ----
STUB_BIN=$(mktemp -d)
trap 'rm -rf "$STUB_BIN"' EXIT
export PATH="$STUB_BIN:$PATH"

# Happy path stub
cat > "$STUB_BIN/curl" << 'EOF'
#!/usr/bin/env bash
echo '{"healthy":true}'
EOF
chmod +x "$STUB_BIN/curl"

check_health "http://fake-host/health" && echo "PASS: healthy response"

Mensimulasikan Kegagalan Perintah

Salah satu kegunaan pengganti yang paling bernilai ialah mensimulasikan kegagalan yang sukar dihasilkan semula dengan alat sebenar — tamat masa rangkaian, ralat kebenaran, cakera penuh atau API jauh yang mengembalikan 500.

Untuk mensimulasikan kegagalan, jadikan pengganti anda keluar dengan kod bukan sifar. Anda juga boleh menulis ke stderr sama seperti yang dilakukan oleh perintah sebenar, supaya pengendalian ralat skrip anda diuji sepenuhnya.

#!/usr/bin/env bash
# Test that check_health handles a curl failure gracefully

check_health() {
  local url="$1"
  local response
  # -f makes curl exit non-zero on HTTP error; -s silences progress
  if ! response=$(curl -sf "$url" 2>/dev/null); then
    echo "ERROR: could not reach $url" >&2
    return 1
  fi
  echo "OK: $response"
}

STUB_BIN=$(mktemp -d)
trap 'rm -rf "$STUB_BIN"' EXIT
export PATH="$STUB_BIN:$PATH"

# Failure stub — simulates a network error (curl exit code 6 = could not resolve host)
cat > "$STUB_BIN/curl" << 'EOF'
#!/usr/bin/env bash
echo 'curl: (6) Could not resolve host: fake-host' >&2
exit 6
EOF
chmod +x "$STUB_BIN/curl"

if ! check_health "http://fake-host/health"; then
  echo "PASS: failure path handled correctly"
fi

Merekod Panggilan Pengganti untuk Pengesahan

Adakalanya anda perlu mengesahkan bukan sahaja apa yang dikeluarkan oleh skrip anda, tetapi juga cara skrip itu memanggil alat luaran — argumen yang dihantar, bilangan kali alat itu dipanggil atau susunan panggilan tersebut. Pengganti pengintip merekodkan panggilannya ke dalam fail.

Selepas ujian, rangka kerja ujian anda membaca fail rekod itu dan mengesahkan kandungannya. Dengan cara ini, anda mendapat pengesahan pada peringkat argumen tanpa rangka kerja khas.

#!/usr/bin/env bash
# Spy stub: record every invocation of 'aws' to a log file

STUB_BIN=$(mktemp -d)
CALL_LOG=$(mktemp)
trap 'rm -rf "$STUB_BIN" "$CALL_LOG"' EXIT
export PATH="$STUB_BIN:$PATH"
export CALL_LOG   # make it available inside the stub

cat > "$STUB_BIN/aws" << 'EOF'
#!/usr/bin/env bash
# Append all arguments to the call log
echo "aws $*" >> "$CALL_LOG"
# Return fake S3 output
echo "upload: ./report.pdf to s3://my-bucket/report.pdf"
exit 0
EOF
chmod +x "$STUB_BIN/aws"

# Simulate the script under test calling aws s3 cp
aws s3 cp report.pdf s3://my-bucket/report.pdf
aws s3 cp logs.tar.gz s3://my-bucket/logs.tar.gz

# Verify calls were made with expected arguments
echo "--- Recorded calls ---"
cat "$CALL_LOG"
grep -q 's3://my-bucket/report.pdf' "$CALL_LOG" && echo "PASS: S3 upload verified"

Menggantikan Berbilang Perintah Serentak

Skrip sebenar sering memanggil beberapa alat luaran. Anda boleh menggantikan semuanya dalam direktori STUB_BIN yang sama. Setiap fail pengganti adalah bebas dan boleh mengembalikan output serta kod keluar yang berbeza.

Pastikan pengganti ringkas: kembalikan hanya perkara yang benar-benar dihuraikan oleh skrip yang sedang diuji. Jangan cuba mensimulasikan setiap bendera — gunakan hanya subset yang digunakan oleh skrip anda.

#!/usr/bin/env bash
# Stub both 'git' and 'docker' for a release script test

STUB_BIN=$(mktemp -d)
trap 'rm -rf "$STUB_BIN"' EXIT
export PATH="$STUB_BIN:$PATH"

# Stub git: pretend we are on tag v2.1.0
cat > "$STUB_BIN/git" << 'EOF'
#!/usr/bin/env bash
case "$*" in
  *"describe --tags"*) echo "v2.1.0" ;;
  *"rev-parse HEAD"*)  echo "abc1234" ;;
  *) echo "[git stub] unhandled: $*" >&2 ; exit 1 ;;
esac
EOF
chmod +x "$STUB_BIN/git"

# Stub docker: pretend build and push succeed
cat > "$STUB_BIN/docker" << 'EOF'
#!/usr/bin/env bash
echo "[docker stub] $*"
exit 0
EOF
chmod +x "$STUB_BIN/docker"

# Simulate the release logic
VERSION=$(git describe --tags)
SHA=$(git rev-parse HEAD)
echo "Building image for version=$VERSION sha=$SHA"
docker build -t "myapp:$VERSION" .
docker push "myapp:$VERSION"

Menggunakan Fungsi sebagai Pengganti (Tiada Fail Diperlukan)

Untuk kes yang mudah, anda tidak perlu menulis fail langsung. Anda boleh mentakrifkan fungsi shell dengan nama yang sama seperti perintah tersebut. Oleh sebab fungsi diselesaikan sebelum carian PATH luaran, fungsi itu akan mendapat keutamaan secara automatik.

Ini ialah pendekatan terpantas untuk menguji unit skrip yang dimuatkan dengan source. Walau bagaimanapun, pengganti berasaskan fungsi hanya berfungsi dalam proses shell yang sama — pengganti itu tidak akan kelihatan kepada subproses yang dimulakan dengan bash -c secara eksplisit atau kepada proses latar. Untuk keadaan tersebut, gunakan pendekatan berasaskan fail.

#!/usr/bin/env bash
# Source the script under test (a small helper library)
source_under_test() {
  # Inline the logic we want to test
  get_instance_id() {
    # Would normally call: curl http://169.254.169.254/latest/meta-data/instance-id
    curl -sf http://169.254.169.254/latest/meta-data/instance-id
  }
}
source_under_test

# Override curl with a shell function stub
curl() {
  echo "i-0abc123def456"
  return 0
}
# Export is NOT needed — function is visible in same shell

# Run the function under test
result=$(get_instance_id)
[[ "$result" == "i-0abc123def456" ]] && echo "PASS: instance ID returned" || echo "FAIL"

Mengeksport Fungsi kepada Subproses

Apabila skrip yang sedang diuji melancarkan subproses (contohnya bash script.sh atau saluran paip), pengganti fungsi shell yang ditakrifkan dalam proses induk secara lalai tidak diwarisi. Anda mempunyai dua pilihan:

  • Gunakan export -f function_name untuk mengeksport fungsi tersebut — fungsi itu akan tersedia kepada proses bash anak
  • Atau gunakan pengganti berasaskan fail dalam direktori STUB_BIN, yang sentiasa berfungsi merentasi sempadan proses

export -f kemas, tetapi hanya berfungsi dengan bash (bukan sh atau shell lain). Utamakan pengganti berasaskan fail dalam persekitaran CI yang menggunakan pelbagai bahasa.

#!/usr/bin/env bash
# Demonstrate export -f for subshell-visible function stubs

# Define the stub in the current shell
curl() {
  echo '{"status":"ok"}'
  return 0
}
# Export the function so child bash processes inherit it
export -f curl

# Verify the stub works in a subshell
bash -c '
  response=$(curl -sf http://api.example.com/status)
  echo "Subshell got: $response"
'

# Without export -f, the subshell would call the real curl
# (or fail if curl is not installed)

Mengintegrasikan Pengganti dengan Rangka Kerja Ujian (BATS)

Apabila anda menggunakan BATS (Sistem Ujian Automatik Bash), penyediaan pengganti hendaklah diletakkan dalam cangkuk setup() dan pembersihan dalam teardown(). BATS menetapkan semula persekitaran antara ujian, jadi setiap ujian mendapat direktori pengganti yang baharu.

Pemboleh ubah BATS seperti $BATS_TEST_TMPDIR memberikan anda direktori sementara untuk setiap ujian secara automatik — gunakan direktori itu dan bukannya mktemp -d untuk kod yang lebih kemas.

#!/usr/bin/env bats
# File: test_deploy.bats
# Run with: bats test_deploy.bats

setup() {
  # BATS provides a unique tmpdir per test
  export STUB_BIN="$BATS_TEST_TMPDIR/stub_bin"
  mkdir -p "$STUB_BIN"
  export PATH="$STUB_BIN:$PATH"

  # Default stub: healthy service
  cat > "$STUB_BIN/curl" << 'EOF'
#!/usr/bin/env bash
echo '{"healthy":true}'
EOF
  chmod +x "$STUB_BIN/curl"
}

teardown() {
  # BATS auto-removes BATS_TEST_TMPDIR, but explicit is safer
  rm -rf "$STUB_BIN"
}

@test "deploy succeeds when service is healthy" {
  run bash deploy.sh
  [ "$status" -eq 0 ]
  [[ "$output" == *"Deploy complete"* ]]
}

@test "deploy aborts when service is down" {
  # Override the stub for this specific test
  echo -e '#!/usr/bin/env bash\nexit 1' > "$STUB_BIN/curl"
  chmod +x "$STUB_BIN/curl"

  run bash deploy.sh
  [ "$status" -ne 0 ]
}

Semakan Pengetahuan: Meniru Perintah dalam Bash

Uji pemahaman anda tentang peniruan perintah dan corak pengganti dalam Bash.

Seorang pembangun menulis ujian yang mentakrifkan fungsi shell bernama aws untuk menggantikan AWS CLI sebenar. Ujian itu berjalan dengan baik terus dari terminal, tetapi apabila saluran paip CI menjalankan skrip yang sedang diuji sebagai bash deploy.sh, pengganti tersebut diabaikan dan perintah aws sebenar dipanggil.

Apakah pembetulan yang betul?

Imbas Kembali: Meniru Perintah dan Menggantikan Alat Luaran

Anda telah mempelajari set alat lengkap untuk menggantikan perintah sebenar dengan pengganti terkawal semasa menguji skrip Bash.

Teknik teras yang dibincangkan:

  • Mendahulukan PATH — cipta direktori STUB_BIN dengan mktemp -d, tulis fail pengganti boleh laku di dalamnya dan letakkan direktori itu di hadapan PATH
  • Kod keluar pengganti — kembalikan 0 untuk kejayaan dan nilai bukan sifar untuk mensimulasikan kegagalan tertentu (ralat rangkaian, kebenaran ditolak dan sebagainya)
  • Pengganti pengintip — tambah argumen pada fail log di dalam pengganti untuk mengesahkan cara skrip anda memanggil alat luaran
  • Berbilang pengganti — letakkan beberapa fail pengganti dalam STUB_BIN yang sama untuk meniru seluruh ekosistem kebergantungan serentak
  • Pengganti fungsi — takrifkan fungsi shell dengan nama yang sama seperti perintah untuk peniruan dalam proses yang sama; gunakan export -f untuk mencapainya dalam proses bash anak
  • Integrasi BATS — gunakan cangkuk setup()/teardown() dan $BATS_TEST_TMPDIR untuk pengasingan yang bersih bagi setiap ujian

Sentiasa gunakan trap '...' EXIT untuk menjamin pembersihan pengganti tanpa mengira hasil ujian. Pastikan pengganti ringkas — kembalikan hanya perkara yang benar-benar dihuraikan oleh skrip anda. Pengganti berasaskan fail ialah pilihan yang paling mudah alih untuk saluran paip CI.

Percuma untuk bermula

Pelajari Bash dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
22
Pelajaran
88

Soalan Lazim

Adakah pelajaran “Meniru Perintah dan Menyediakan Alat Luaran Palsu” percuma?

Ya — teks penuh “Meniru Perintah dan Menyediakan Alat Luaran Palsu” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus Penguasaan Baris Perintah Linux &amp; Penskripan Bash, tingkat taraf kepada CoddyKit PRO. Kursus Penguasaan Baris Perintah Linux &amp; Penskripan Bash merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Meniru Perintah dan Menyediakan Alat Luaran Palsu”?

Gantikan PATH dan takrifkan binari palsu untuk menguji skrip tanpa menyentuh sistem sebenar Anda berlatih Penguasaan Baris Perintah Linux &amp; Penskripan Bash menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Penguasaan Baris Perintah Linux &amp; Penskripan Bash?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Penguasaan Baris Perintah Linux &amp; Penskripan Bash di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 2 daripada 4.

Berapa lamakah pelajaran “Meniru Perintah dan Menyediakan Alat Luaran Palsu” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Penguasaan Baris Perintah Linux &amp; Penskripan Bash ini?

Ya. Setiap pelajaran Penguasaan Baris Perintah Linux &amp; Penskripan Bash menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Pengujian Unit Fungsi dengan Bats-core
  2. Meniru Perintah dan Menyediakan Alat Luaran Palsu
  3. Lekapan Ujian, Persekitaran Sementara dan Liputan
  4. Menjalankan Ujian Shell dalam Saluran Paip CI
← Kembali ke Penguasaan Baris Perintah Linux &amp; Penskripan Bash