0Pricing
Linux Command Line & Bash Scripting Mastery · บทเรียน

ฟิกซ์เจอร์ สภาพแวดล้อมชั่วคราว และความครอบคลุม

สร้างฟิกซ์เจอร์ทดสอบที่แยกจากกัน และวัดว่าแบบทดสอบของคุณครอบคลุมแขนงใดของสคริปต์จริง

ฟิกซ์เจอร์ สภาพแวดล้อมชั่วคราว และความครอบคลุม เป็นบทเรียน Linux Command Line & Bash Scripting Mastery ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Linux Command Line & Bash Scripting Mastery และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Linux Command Line & Bash Scripting Mastery มีบทเรียนทั้งหมด 4 บทเรียน

เหตุใดฟิกซ์เจอร์และการแยกสภาพแวดล้อมจึงสำคัญ

เมื่อทดสอบสคริปต์ Bash ความเสี่ยงที่ใหญ่ที่สุดคือผลข้างเคียง: การทดสอบของคุณอาจแก้ไขไฟล์จริง ฐานข้อมูลจริง หรือสถานะของระบบจริงโดยไม่ได้ตั้งใจ การทดสอบที่ผ่านบนเครื่องของคุณแต่ทำให้ข้อมูลในระบบจริงเสียหาย ย่อมแย่กว่าการไม่มีการทดสอบเลย

วิธีแก้คือฟิกซ์เจอร์การทดสอบ ซึ่งเป็นสภาพแวดล้อมที่ควบคุมได้และทิ้งได้ ออกแบบให้เลียนแบบเงื่อนไขจริงโดยไม่แตะต้องสิ่งใดที่เป็นของจริง ฟิกซ์เจอร์ที่ดีช่วยให้คุณได้:

  • ทำซ้ำได้ — การทดสอบให้ผลลัพธ์เดิมทุกครั้ง
  • แยกจากกัน — การทดสอบไม่รบกวนกันเองหรือโฮสต์
  • ปลอดภัย — การดำเนินการที่ทำลายข้อมูลจะกระทบเฉพาะข้อมูลที่ทิ้งได้
  • รวดเร็ว — ไม่มีการเรียกเครือข่ายหรือการรับส่งข้อมูลปริมาณมาก เว้นแต่จำเป็นอย่างยิ่ง

ในการทดสอบ Bash ฟิกซ์เจอร์มักเป็นไดเรกทอรีชั่วคราวที่เติมด้วยไฟล์ที่ทราบแน่ชัด ไฟล์ปฏิบัติการจำลองที่วางไว้ช่วงต้นของ $PATH และตัวแปรสภาพแวดล้อมที่มีขอบเขตอยู่ในกระบวนการทดสอบ

การสร้างและล้างไดเรกทอรีชั่วคราว

รูปแบบมาตรฐานสำหรับไดเรกทอรีชั่วคราวแยกต่อการทดสอบ ใช้ mktemp -d ซึ่งจะสร้างไดเรกทอรีที่มีชื่อไม่ซ้ำกันใน /tmp และแสดงเส้นทางออกมา คุณเก็บเส้นทางนั้นไว้และลงทะเบียน trap เพื่อลบไดเรกทอรีโดยอัตโนมัติเมื่อเชลล์จบการทำงาน แม้จะจบลงเพราะข้อผิดพลาดก็ตาม

สำนวนสองบรรทัดนี้ควรปรากฏในทุกไฟล์การทดสอบที่แตะต้องระบบไฟล์:

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

# Create an isolated temp directory
TMPDIR=$(mktemp -d)
# Always clean up, even if the script exits early or errors out
trap 'rm -rf "$TMPDIR"' EXIT

echo "Working in: $TMPDIR"

# Simulate creating fixture files
mkdir -p "$TMPDIR/project/{src,tests,logs}"
echo 'version=1.2.3' > "$TMPDIR/project/.env"
echo 'Hello fixture' > "$TMPDIR/project/src/main.sh"

ls -R "$TMPDIR/project"
echo 'Temp dir will be removed automatically on exit'

การจัดโครงสร้างต้นไม้ไดเรกทอรีฟิกซ์เจอร์

ฟิกซ์เจอร์ที่จัดโครงสร้างดีจะจำลองผังไดเรกทอรีที่สคริปต์ที่กำลังทดสอบคาดหวังจริง ๆ ให้มองว่าฟิกซ์เจอร์เป็นรากโครงการจำลองขนาดเล็ก ฟังก์ชันเตรียมฟิกซ์เจอร์จะสร้างผังนี้ก่อนการทดสอบแต่ละครั้ง และการล้างข้อมูลจะลบผังดังกล่าว

แนวปฏิบัติสำคัญ:

  • ใช้ฟังก์ชัน setup() ที่เฟรมเวิร์กการทดสอบเรียกก่อนการทดสอบแต่ละครั้ง
  • ใช้ teardown() หรือ cleanup() ที่ทำงานหลังการทดสอบแต่ละครั้ง แม้การทดสอบจะล้มเหลว
  • ทำให้ไฟล์ฟิกซ์เจอร์มีขนาดเล็กที่สุด — มีเฉพาะสิ่งที่สคริปต์อ่านจริง ๆ
  • ตั้งชื่อไฟล์ฟิกซ์เจอร์ให้สื่อความหมาย เพื่อให้วินิจฉัยความล้มเหลวได้ง่าย
#!/usr/bin/env bash
# fixture_helpers.bash — source this from your test files

FIXTURE_ROOT=''

setup_fixture() {
  FIXTURE_ROOT=$(mktemp -d)
  # Build the directory tree the deploy script expects
  mkdir -p "$FIXTURE_ROOT"/{dist,config,logs}
  echo '{"version":"2.0"}' > "$FIXTURE_ROOT/config/app.json"
  echo 'console.log("app")' > "$FIXTURE_ROOT/dist/index.js"
  touch "$FIXTURE_ROOT/logs/.gitkeep"
  export FIXTURE_ROOT
  echo "[setup] Fixture ready at $FIXTURE_ROOT"
}

teardown_fixture() {
  if [[ -n "$FIXTURE_ROOT" && -d "$FIXTURE_ROOT" ]]; then
    rm -rf "$FIXTURE_ROOT"
    echo '[teardown] Fixture removed'
  fi
}

# Self-test
setup_fixture
ls "$FIXTURE_ROOT"
teardown_fixture

การจำลองไฟล์ปฏิบัติการด้วย PATH ปลอม

สคริปต์ Bash จำนวนมากเรียกใช้เครื่องมือภายนอก เช่น curl, aws, docker หรือ git ในการทดสอบ คุณไม่ต้องการเชื่อมต่อบริการจริง จึงแทนที่เครื่องมือเหล่านั้นด้วยไฟล์ปฏิบัติการปลอม

เทคนิคนี้ทำได้ง่าย:

  1. สร้างไดเรกทอรีชั่วคราว bin/ ภายในฟิกซ์เจอร์
  2. เขียนสคริปต์เชลล์ขนาดเล็กที่มีชื่อเดียวกับเครื่องมือจริงไว้ในไดเรกทอรีนั้น
  3. เพิ่มไดเรกทอรีดังกล่าวไว้หน้าสุดของ $PATH ก่อนเรียกใช้สคริปต์ที่กำลังทดสอบ

เนื่องจากระบบค้นหา $PATH จากซ้ายไปขวา ไฟล์ปลอมจึงถูกเลือกใช้ และไบนารีจริงจะไม่ถูกเรียกใช้

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

FIXTURE=$(mktemp -d)
trap 'rm -rf "$FIXTURE"' EXIT

# Create a fake 'curl' that records calls and returns canned data
FAKE_BIN="$FIXTURE/bin"
mkdir -p "$FAKE_BIN"

cat > "$FAKE_BIN/curl" << 'SCRIPT'
#!/usr/bin/env bash
# Log every argument for later inspection
echo "curl $*" >> "$FIXTURE_BIN_LOG"
# Return a canned HTTP 200 response body
echo '{"status":"ok","id":42}'
SCRIPT
chmod +x "$FAKE_BIN/curl"

# Export the log path so the fake can find it
export FIXTURE_BIN_LOG="$FIXTURE/curl_calls.log"

# Prepend fake bin directory to PATH
export PATH="$FAKE_BIN:$PATH"

# Now any call to 'curl' hits our fake
curl -s https://api.example.com/health
curl -X POST https://api.example.com/deploy

echo '--- Recorded curl calls ---'
cat "$FIXTURE_BIN_LOG"

การเก็บและตรวจสอบผลลัพธ์ของคำสั่ง

ฟิกซ์เจอร์จะมีประโยชน์ก็ต่อเมื่อคุณสามารถตรวจสอบสิ่งที่สคริปต์ทำได้ รูปแบบมาตรฐานมีดังนี้:

  • เก็บ stdout/stderr ลงในตัวแปรด้วย $() หรือการแทนที่กระบวนการ
  • ตรวจสอบไฟล์บันทึกที่ไบนารีปลอมเขียนไว้
  • ตรวจสอบรหัสจบการทำงานอย่างชัดเจนด้วย $? หรือตรรกะเงื่อนไข
  • ตรวจสอบว่าไฟล์บางไฟล์ถูกสร้าง แก้ไข หรือไม่มีการแตะต้อง

การเขียนตัวช่วยตรวจสอบขนาดเล็กที่มุ่งเน้นเฉพาะเรื่องจะทำให้การทดสอบอ่านง่าย และให้ข้อความความล้มเหลวที่แม่นยำเมื่อเกิดข้อผิดพลาด

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

# Minimal assertion helpers
assert_eq() {
  local desc="$1" expected="$2" actual="$3"
  if [[ "$expected" == "$actual" ]]; then
    echo "PASS: $desc"
  else
    echo "FAIL: $desc"
    echo "  expected: $expected"
    echo "  actual:   $actual"
    return 1
  fi
}

assert_file_exists() {
  local desc="$1" file="$2"
  if [[ -f "$file" ]]; then
    echo "PASS: $desc"
  else
    echo "FAIL: $desc — file not found: $file"
    return 1
  fi
}

assert_contains() {
  local desc="$1" needle="$2" haystack="$3"
  if [[ "$haystack" == *"$needle"* ]]; then
    echo "PASS: $desc"
  else
    echo "FAIL: $desc — '$needle' not found in output"
    return 1
  fi
}

# Demo usage
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT
echo 'hello world' > "$TMPDIR/greeting.txt"
OUT=$(cat "$TMPDIR/greeting.txt")
assert_eq   'file content matches'     'hello world' "$OUT"
assert_file_exists 'greeting file created' "$TMPDIR/greeting.txt"
assert_contains    'output has hello'     'hello'       "$OUT"

การกำหนดขอบเขตตัวแปรสภาพแวดล้อมในการทดสอบ

สคริปต์มักอ่านค่าจากตัวแปรสภาพแวดล้อม เช่น $HOME, $CONFIG_PATH หรือ $DATABASE_URL ในการทดสอบ คุณต้องแทนที่ค่าเหล่านี้โดยไม่ทำให้สภาพแวดล้อมจริงปนเปื้อน

แนวทางที่ปลอดภัยที่สุดคือเรียกใช้สคริปต์ที่กำลังทดสอบในเชลล์ย่อย โดยมีเฉพาะตัวแปรที่คุณกำหนดไว้อย่างชัดเจน คำสั่ง env ช่วยให้คุณล้างตัวแปรสภาพแวดล้อมทั้งหมดแล้วเพิ่มกลับเฉพาะค่าที่ต้องการได้:

  • env -i VAR=val ./script.sh — สภาพแวดล้อมที่สะอาดทั้งหมด
  • (export VAR=val; ./script.sh) — เชลล์ย่อยสืบทอดสภาพแวดล้อมของกระบวนการแม่ พร้อมค่าที่คุณแทนที่

การใช้เชลล์ย่อยยังหมายความว่า หากสคริปต์เปลี่ยนค่า $IFS, $PWD หรือสถานะส่วนกลางอื่น ๆ การเปลี่ยนแปลงเหล่านั้นจะไม่รั่วไหลกลับไปยังตัวเรียกใช้การทดสอบ

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

FIXTURE=$(mktemp -d)
trap 'rm -rf "$FIXTURE"' EXIT

# Write a tiny script under test that reads env vars
cat > "$FIXTURE/deploy.sh" << 'SCRIPT'
#!/usr/bin/env bash
set -euo pipefail
ENV_NAME=${DEPLOY_ENV:-unknown}
CFG=${CONFIG_DIR:-/etc/app}
echo "Deploying to $ENV_NAME using config from $CFG"
SCRIPT
chmod +x "$FIXTURE/deploy.sh"

echo '--- Test 1: staging env ---'
# Run in a clean subshell with explicit vars
(
  export DEPLOY_ENV=staging
  export CONFIG_DIR="$FIXTURE/config"
  "$FIXTURE/deploy.sh"
)

echo '--- Test 2: production env ---'
(
  export DEPLOY_ENV=production
  export CONFIG_DIR=/etc/prod-config
  "$FIXTURE/deploy.sh"
)

echo '--- Test 3: defaults ---'
# No env vars set — script should use its own defaults
env -i PATH="$PATH" "$FIXTURE/deploy.sh"

บทนำสู่ kcov สำหรับการวัดความครอบคลุมของ Bash

ความครอบคลุมตอบคำถามว่า การทดสอบเรียกใช้บรรทัด (และแขนง) ใดของสคริปต์จริงบ้าง ตัวเลขความครอบคลุมสูงไม่ได้รับประกันความถูกต้อง แต่ค่าต่ำจะเผยให้เห็นเส้นทางที่ยังไม่ได้ทดสอบและอาจมีข้อบกพร่องซ่อนอยู่

เครื่องมือหลักสำหรับวัดความครอบคลุมของ Bash คือ kcov เครื่องมือนี้ทำงานโดยติดตั้งเครื่องมือวัดในสคริปต์ระดับ OS ด้วย PTRACE (Linux) หรือ dtrace (macOS) จึงไม่จำเป็นต้องแก้ไขซอร์สโค้ด และจะสร้างรายงาน HTML ที่แสดงบรรทัดสีแดง (ยังไม่ครอบคลุม) และสีเขียว (ครอบคลุมแล้ว)

การใช้งานพื้นฐาน:

  • kcov --include-path=./src coverage-out/ ./src/myscript.sh
  • เปิด coverage-out/index.html ในเบราว์เซอร์เพื่อตรวจสอบผลลัพธ์
  • ใน CI ให้วิเคราะห์ coverage-out/myscript.sh/coverage.json เพื่ออ่านเปอร์เซ็นต์ในรูปแบบที่เครื่องอ่านได้

หมายเหตุ: ต้องติดตั้ง kcov แยกต่างหาก (brew install kcov บน macOS และ apt install kcov บน Ubuntu 20.04 ขึ้นไป)

การเรียกใช้ kcov กับสคริปต์จริง

ตัวอย่างแบบครบตั้งแต่ต้นจนจบนี้แสดงสคริปต์ที่พร้อมนำไปใช้งาน การทดสอบที่เรียกใช้สคริปต์นั้น และการเรียกใช้ kcov เพื่อวัดความครอบคลุม โปรดสังเกตว่าไดเรกทอรีผลลัพธ์แยกตามการทดสอบ เพื่อให้คุณรวมผลจากการทดสอบหลายครั้งได้ในภายหลัง

#!/usr/bin/env bash
# This demo shows the *structure* of a kcov workflow.
# It will not run kcov itself (not guaranteed to be installed),
# but the script under test and test runner are fully runnable.
set -euo pipefail

FIXTURE=$(mktemp -d)
trap 'rm -rf "$FIXTURE"' EXIT

# 1. Script under test
cat > "$FIXTURE/process.sh" << 'SCRIPT'
#!/usr/bin/env bash
set -euo pipefail
INPUT="$1"
if [[ ! -f "$INPUT" ]]; then
  echo "ERROR: file not found" >&2
  exit 1
fi
LINE_COUNT=$(wc -l < "$INPUT")
if (( LINE_COUNT == 0 )); then
  echo "WARNING: file is empty"
else
  echo "Processed $LINE_COUNT lines"
fi
SCRIPT
chmod +x "$FIXTURE/process.sh"

# 2. Happy path test (exercises line 6 and 11)
echo -e 'one\ntwo\nthree' > "$FIXTURE/data.txt"
OUT=$("$FIXTURE/process.sh" "$FIXTURE/data.txt")
echo "Happy path: $OUT"

# 3. Empty file test (exercises line 9)
touch "$FIXTURE/empty.txt"
OUT=$("$FIXTURE/process.sh" "$FIXTURE/empty.txt")
echo "Empty file: $OUT"

# 4. Missing file test (exercises line 5-6)
if ! OUT=$("$FIXTURE/process.sh" "$FIXTURE/missing.txt" 2>&1); then
  echo "Missing file (expected error): $OUT"
fi

# To measure coverage, wrap each call with kcov:
# kcov --include-path="$FIXTURE" "$FIXTURE/cov/happy" "$FIXTURE/process.sh" ...
# kcov --merge "$FIXTURE/cov/all" "$FIXTURE/cov/happy" "$FIXTURE/cov/empty"

การรวมความครอบคลุมจากการทดสอบหลายครั้ง

การทดสอบเพียงครั้งเดียวแทบไม่ครอบคลุมทุกแขนง คุณจึงเรียกใช้การทดสอบหลายครั้ง โดยแต่ละครั้งใช้ไดเรกทอรีผลลัพธ์ความครอบคลุมของตนเอง แล้วจึงรวมผลเข้าด้วยกัน แฟล็ก --merge ของ kcov จะรวมการเรียกใช้หลายครั้งเป็นรายงานแบบรวมหนึ่งเดียว

รูปแบบทั่วไปในไปป์ไลน์ CI:

  • เรียกใช้การทดสอบ A → ส่งผลลัพธ์ไปที่ cov/test_a/
  • เรียกใช้การทดสอบ B → ส่งผลลัพธ์ไปที่ cov/test_b/
  • รวมผล → kcov --merge cov/all/ cov/test_a/ cov/test_b/
  • วิเคราะห์ cov/all/<script>/coverage.json เพื่อรับเปอร์เซ็นต์สุดท้าย

คุณยังสามารถกำหนดเกณฑ์ขั้นต่ำและทำให้การสร้าง CI ล้มเหลวหากความครอบคลุมลดต่ำกว่าเกณฑ์ดังกล่าวได้:

#!/usr/bin/env bash
# extract_coverage.sh — parse kcov JSON and fail below threshold
set -euo pipefail

MIN_COVERAGE=80   # percent
COV_JSON="${1:-coverage-out/myscript.sh/coverage.json}"

if [[ ! -f "$COV_JSON" ]]; then
  echo "ERROR: coverage JSON not found at $COV_JSON" >&2
  exit 1
fi

# kcov JSON contains a key like: "percent_covered": "87.50"
PERCENT=$(grep -oP '"percent_covered":\s*"\K[0-9.]+' "$COV_JSON")
PERCENT_INT=${PERCENT%%.*}   # truncate decimal

echo "Coverage: ${PERCENT}%  (minimum: ${MIN_COVERAGE}%)"

if (( PERCENT_INT < MIN_COVERAGE )); then
  echo "FAIL: coverage ${PERCENT}% is below threshold ${MIN_COVERAGE}%" >&2
  exit 1
fi

echo "PASS: coverage threshold met"

ความครอบคลุมแขนงเทียบกับความครอบคลุมบรรทัด

คุณจะพบตัวชี้วัดความครอบคลุมหลักอยู่สองประเภท:

  • ความครอบคลุมบรรทัด — บรรทัดนี้ถูกเรียกใช้หรือไม่ ง่ายต่อการทำให้ตัวเลขดูดีเกินจริง: การทดสอบเพียงครั้งเดียวอาจแตะต้องหลายบรรทัด แต่พลาดเส้นทางเงื่อนไขที่สำคัญ
  • ความครอบคลุมแขนง — แต่ละแขนงของ if, case และ &&/|| ถูกเลือกใช้หรือไม่ ตัวชี้วัดนี้สะท้อนผลได้ดีกว่ามาก และต้องมีการทดสอบทั้งด้านจริงและด้านเท็จของทุกการตัดสินใจ

kcov รายงานทั้งสองค่า ข้อสังเกตสำคัญคือ ความครอบคลุมบรรทัด 100% ไม่ได้หมายความว่าความครอบคลุมแขนงจะเป็น 100% ลองพิจารณาสคริปต์นี้ การทดสอบเพียงครั้งเดียวที่ใช้ไฟล์ไม่ว่างจะครอบคลุมทุกบรรทัด แต่จะไม่เคยเข้าถึงแขนงไฟล์ว่าง (บรรทัดที่ 9 ด้านล่าง):

#!/usr/bin/env bash
# Illustrates line vs branch coverage gap
set -euo pipefail

check_file() {
  local f="$1"
  if [[ -f "$f" ]]; then        # branch A (true) OR branch B (false)
    local lines
    lines=$(wc -l < "$f")
    if (( lines > 0 )); then    # branch C (true) OR branch D (false)
      echo "File has $lines lines"
    else
      echo "File is empty"     # branch D — unreached if only tested with non-empty file
    fi
  else
    echo "File missing"        # branch B — unreached if only tested with existing file
  fi
}

# Only one test: covers lines 5-10 (4 of 6 branches)
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT
echo 'data' > "$TMPDIR/sample.txt"
check_file "$TMPDIR/sample.txt"

# To reach 100% branch coverage you also need:
# check_file "/nonexistent/path"
# check_file "$TMPDIR/empty.txt" (after: touch "$TMPDIR/empty.txt")

ผสาน Fixture และ Coverage ใน CI

เมื่อนำทุกอย่างมารวมกัน: pipeline CI ที่มีความทนทานสำหรับโครงการ Bash จะรวมการตั้งค่า fixture การเรียกใช้ test ภายใต้ kcov การผสานผล และการตรวจสอบค่าขั้นต่ำไว้ในสคริปต์เดียว สคริปต์นี้จะเป็นจุดเริ่มต้นของ CI — ใช้คำสั่งเดียวเพื่อเรียกใช้ทุกอย่าง

หลักการออกแบบสำหรับตัวเรียกใช้ test ของ CI:

  • test แต่ละกรณีเรียกใช้ setup_fixture และลงทะเบียน teardown_fixture ผ่าน trap
  • เรียกใช้สคริปต์ที่กำลังทดสอบด้วย $PATH จำลองและตัวแปรสภาพแวดล้อมที่จำกัดขอบเขต
  • kcov ครอบการเรียกใช้แต่ละครั้งและเขียนผลลงในไดเรกทอรีย่อยที่มีหมายเลขกำกับ
  • หลังจาก test ทั้งหมดเสร็จสิ้น kcov จะผสานผล และสคริปต์ตรวจสอบค่าขั้นต่ำจะเป็นตัวตัดสินว่าจะให้ build ผ่านหรือไม่
  • ตัวเรียกใช้ CI จะจบการทำงานด้วยค่าที่ไม่ใช่ศูนย์ หาก test ใด ๆ หรือตัวตรวจสอบ coverage ล้มเหลว
#!/usr/bin/env bash
# ci_runner.sh — full fixture + coverage pipeline entry point
set -euo pipefail

SRC="./src/deploy.sh"
COV_ROOT="$(mktemp -d)/coverage"
trap 'rm -rf "$COV_ROOT"' EXIT
mkdir -p "$COV_ROOT"

PASS=0
FAIL=0
RUN_NUM=0

run_test() {
  local name="$1" test_fn="$2"
  local fixture
  fixture=$(mktemp -d)
  local cov_out="$COV_ROOT/run_$((++RUN_NUM))"

  if (
    trap 'rm -rf "$fixture"' EXIT
    export FIXTURE="$fixture"
    # Fake bin directory shadowing real tools
    mkdir -p "$fixture/bin"
    export PATH="$fixture/bin:$PATH"
    "$test_fn" "$fixture"
  ); then
    echo "PASS: $name"
    (( PASS++ )) || true
  else
    echo "FAIL: $name"
    (( FAIL++ )) || true
  fi
}

# Example test function
test_happy_path() {
  local fx="$1"
  mkdir -p "$fx/dist"
  echo 'app.js' > "$fx/dist/index.js"
  # Would normally run: kcov "$cov_out" "$SRC" --env=staging "$fx"
  echo "[test] happy path executed in $fx"
}

run_test 'happy_path' test_happy_path

echo "Results: $PASS passed, $FAIL failed"
(( FAIL == 0 ))

ตรวจสอบความรู้: เทคนิค PATH จำลอง

ทดสอบความเข้าใจของคุณเกี่ยวกับเทคนิค PATH จำลองที่ใช้ใน fixture สำหรับ test ของ Bash

ทบทวน: Fixture สภาพแวดล้อมชั่วคราว และ Coverage

บทเรียนนี้ครอบคลุมชุดเครื่องมือทั้งหมดสำหรับการทดสอบ Bash ที่น่าเชื่อถือและแยกออกจากกัน:

  • ไดเรกทอรีชั่วคราว — mktemp -d ร่วมกับ trap ... EXIT รับประกันการล้างข้อมูลโดยอัตโนมัติ ไม่ว่า test จะจบลงอย่างไร
  • โครงสร้าง Fixture — คู่ setup_fixture / teardown_fixture จะสร้างและลบทรีไดเรกทอรีขนาดเล็กที่จำลองอินพุตจริงของสคริปต์
  • PATH จำลอง — วางโปรแกรมปฏิบัติการจำลองไว้ใน $FIXTURE/bin/ และเพิ่มไว้หน้าสุดของ $PATH เพื่อดักการเรียกใช้ curl, aws, docker หรือเครื่องมือภายนอกใด ๆ โดยไม่แตะต้องไบนารีของระบบ
  • การจำกัดขอบเขตสภาพแวดล้อม — เรียกใช้สคริปต์ที่กำลังทดสอบใน subshell (() หรือ env -i) เพื่อไม่ให้ตัวแปรที่เปลี่ยนแปลงรั่วไหลกลับไปยังตัวเรียกใช้ test
  • การยืนยันผล — ฟังก์ชันตัวช่วยขนาดเล็ก (assert_eq, assert_file_exists, assert_contains) จะแสดงผลผ่าน/ไม่ผ่านที่เข้าใจง่ายและข้อความแสดงข้อผิดพลาดที่มีความหมาย
  • Coverage ด้วย kcov — ครอบการเรียกใช้สคริปต์โดยไม่ต้องแก้ไขซอร์ส และสร้างรายงาน HTML กับ JSON สำหรับ coverage ระดับบรรทัดและสาขา
  • การผสานและค่าขั้นต่ำ — รวมการเรียกใช้ kcov หลายครั้งด้วย --merge แยกวิเคราะห์ JSON และทำให้ CI ไม่ผ่านหาก coverage ลดลงต่ำกว่าค่าขั้นต่ำที่กำหนด
  • Coverage ระดับสาขากับระดับบรรทัด — ควรตั้งเป้า coverage ระดับสาขาเสมอ เพราะ coverage ระดับบรรทัดเพียงอย่างเดียวอาจพลาดเส้นทางเงื่อนไขทั้งหมดบางเส้นทางและทำให้เกิดความมั่นใจที่ผิดพลาด

ด้วยเทคนิคเหล่านี้ test ของ Bash จะเข้มงวดไม่แพ้ test ของภาษาแบบคอมไพล์ใด ๆ

คำถามที่พบบ่อย

บทเรียน “ฟิกซ์เจอร์ สภาพแวดล้อมชั่วคราว และความครอบคลุม” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ฟิกซ์เจอร์ สภาพแวดล้อมชั่วคราว และความครอบคลุม” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Linux Command Line & Bash Scripting Mastery ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Linux Command Line & Bash Scripting Mastery มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ฟิกซ์เจอร์ สภาพแวดล้อมชั่วคราว และความครอบคลุม”

สร้างฟิกซ์เจอร์ทดสอบที่แยกจากกัน และวัดว่าแบบทดสอบของคุณครอบคลุมแขนงใดของสคริปต์จริง คุณปฏิบัติ Linux Command Line & Bash Scripting Mastery ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Linux Command Line & Bash Scripting Mastery หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Linux Command Line & Bash Scripting Mastery บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “ฟิกซ์เจอร์ สภาพแวดล้อมชั่วคราว และความครอบคลุม” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Linux Command Line & Bash Scripting Mastery นี้ได้ไหม

ได้ บทเรียน Linux Command Line & Bash Scripting Mastery ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การทดสอบฟังก์ชันแบบยูนิตด้วย Bats-core
  2. การจำลองคำสั่งและการทำเครื่องมือภายนอกเป็นสตับ
  3. ฟิกซ์เจอร์ สภาพแวดล้อมชั่วคราว และความครอบคลุม
  4. การเรียกใช้การทดสอบ Shell ในไปป์ไลน์ CI
← กลับไปที่ Linux Command Line & Bash Scripting Mastery