Mocka kommandon och stubba externa verktyg
Ändra PATH och definiera falska binärer för att testa skript utan att påverka riktiga system.
Mocka kommandon och stubba externa verktyg är en gratis lektion i Bemästra Linux-kommandoraden och Bash-skriptning på CoddyKit. Detta är lektion 2 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Bemästra Linux-kommandoraden och Bash-skriptning, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Bemästra Linux-kommandoraden och Bash-skriptning innehåller totalt 4 lektioner.
Varför mocka kommandon i Bash-tester?
När Ni testar ett Bash-skript som anropar curl, aws, git eller något annat externt verktyg uppstår ett problem: riktiga anrop når nätverket, ändrar tillstånd, kostar pengar eller misslyckas helt enkelt i en CI-miljö där verktygen inte är installerade.
Mocking innebär att det riktiga kommandot ersätts med ett falskt som Ni kontrollerar. Er falska implementation (en stub) returnerar förutsägbara utdata och slutstatusar, så att testet blir snabbt, isolerat och reproducerbart.
- Ingen åtkomst till nätverk eller molntjänster behövs
- Tester körs på millisekunder i stället för sekunder
- Ni kan simulera fel som är svåra att utlösa i riktiga system
- CI-pipelines förblir rena och fria från beroenden
Bash ger Er en förvånansvärt enkel mekanism för detta: placera bara Er falska binärfil någonstans tidigare i $PATH än den riktiga.
Så fungerar PATH-sökning
När shellen kör ett kommando som curl söker den igenom varje katalog i $PATH från vänster till höger och kör den första träff den hittar.
Det innebär att shellen aldrig når /usr/bin/curl om Ni lägger till en katalog först som innehåller Ert eget curl-skript.
Mönstret för att åsidosätta kommandon:
- Skapa en temporär katalog (Er stub-bin)
- Skriv en falsk körbar fil med samma namn som det riktiga kommandot
- Lägg till katalogen först i
PATH - Kör skriptet som testas — det anropar Er stub i stället för den riktiga binärfilen
- Städa bort den temporära katalogen efter testet
Detta fungerar utan root-åtkomst, utan att systemfiler ändras och utan något särskilt ramverk.
Skapa en stubkatalog
mktemp -d för att skapa en isolerad temporär katalog för Era stubbar. Varje test eller testsvit får sin egen katalog, vilket förhindrar att tester påverkar varandra.
När testet är klart tar Ni bort katalogen med rm -rf. Med en trap säkerställs städningen även när testet avslutas i förtid på grund av ett fel.
#!/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."Skriv Er första stub
En stub är helt enkelt en körbar fil med samma namn som kommandot Ni vill ersätta. Den skriver ut den utdata som skriptet som testas förväntar sig och avslutas med den kod Ni väljer.
Viktiga regler för stubbar:
- Filen måste vara körbar (
chmod +x) - Shebang-raden (
#!/usr/bin/env bash) krävs - Skriv ut den utdata som Ert riktiga skript skulle tolka
- Använd
exit 0vid lyckat resultat och ett värde som inte är noll vid simulerade fel
#!/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/versionTesta ett skript som anropar curl
Nu sätter vi ihop delarna. Anta att Ni har ett distributionsskript som anropar curl för att kontrollera en hälsoendpunkt och sedan avslutas med ett fel om tjänsten inte är frisk. Ni vill testa både det lyckade fallet och felvägen utan en riktig server.
#!/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"Simulera kommandofel
En av de mest värdefulla användningarna av stubbar är att simulera fel som är svåra att återskapa med riktiga verktyg – nätverkstimeouter, behörighetsfel, fulla diskar eller ett fjärr-API som returnerar 500.
För att simulera ett fel låter du helt enkelt stubben avslutas med en kod som inte är noll. Du kan också skriva till stderr precis som det riktiga kommandot skulle göra, så att skriptets felhantering testas fullt ut.
#!/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"
fiLogga stubbanrop för verifiering
Ibland behöver du kontrollera inte bara vad skriptet skriver ut, utan också hur det anropar ett externt verktyg – vilka argument det skickar, hur många gånger det anropas eller i vilken ordning. En spionstub loggar sina anrop till en fil.
Efter testet läser testharnessen loggfilen och kontrollerar dess innehåll. Det ger dig verifiering på argumentnivå utan något särskilt ramverk.
#!/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"Stubbning av flera kommandon samtidigt
Ett verkligt skript anropar ofta flera externa verktyg. Du kan stubba alla i samma STUB_BIN-katalog. Varje stubfil är fristående och kan returnera olika utdata och avslutskoder.
Håll stubbarna minimala: returnera bara det som skriptet under test faktiskt tolkar. Försök inte simulera alla flaggor – använd bara den delmängd som skriptet använder.
#!/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"Använda funktioner som stubbar (inga filer behövs)
I enkla fall behöver du inte skriva några filer alls. Du kan definiera en skalfunktion med samma namn som kommandot. Eftersom funktioner matchas före sökning i den externa PATH:en får de automatiskt företräde.
Detta är den snabbaste metoden för enhetstestning av skript som läses in med source. Funktionsstubbar fungerar dock bara i samma skalprocess – de är inte synliga för underskal som startas med uttryckligt bash -c eller för bakgrundsprocesser. Använd den filbaserade metoden i sådana fall.
#!/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"Exportera funktioner till underskal
När skriptet under test startar ett underskal (t.ex. bash script.sh eller en pipeline) är skalfunktioner som definierats i det överordnade skalet intevs ärvs som standard. Du har två alternativ:
- Använd
export -f function_nameför att exportera funktionen – då blir den tillgänglig i underordnadebash-processer - Eller använd filbaserade stubbar i en
STUB_BIN-katalog, vilket alltid fungerar över processgränser
export -f är elegant, men fungerar bara med bash (inte med sh eller andra skal). Föredra filbaserade stubbar i polyglotta CI-miljöer.
#!/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)Integrera stubbar med ett testramverk (BATS)
När du använder BATS (Bash Automated Testing System) hör stubbförberedelserna hemma i hooken setup(), och nedstängningen i teardown(). BATS återställer miljön mellan testerna, så varje test får en ny stubkatalog.
BATS-variabler som $BATS_TEST_TMPDIR ger dig automatiskt en temporär katalog per test – använd den i stället för mktemp -d för renare kod.
#!/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 ]
}Kunskapskontroll: Mockning av kommandon i Bash
Testa dina kunskaper om kommandomockning och stubbmönster i Bash.
En utvecklare skriver ett test som definierar en skalfunktion med namnet aws för att stubba det riktiga AWS CLI. Testet fungerar bra när det körs direkt i terminalen, men när CI-pipelinen kör skriptet under test som bash deploy.sh ignoreras stubben och det riktiga kommandot aws anropas.
Vad är den korrekta lösningen?
Sammanfattning: Mocka kommandon och stubba externa verktyg
Du har lärt dig hela verktygslådan för att ersätta riktiga kommandon med kontrollerade ersättningar när du testar Bash-skript.
Viktiga tekniker:
- PATH-företräde – skapa en
STUB_BIN-katalog medmktemp -d, skriv körbara stubfiler där och placera katalogen först iPATH - Stubbers avslutskoder – returnera
0vid lyckat resultat och värden som inte är noll för att simulera specifika fel (nätverksfel, nekad åtkomst osv.) - Spionstubbar – lägg till argument i en loggfil inifrån stubben för att kontrollera hur skriptet anropade externa verktyg
- Flera stubbar – placera flera stubfiler i samma
STUB_BINför att mocka ett helt ekosystem av beroenden samtidigt - Funktionsstubbar – definiera en skalfunktion med samma namn som ett kommando för mockning i samma process; använd
export -fför att nå underordnade bash-processer - BATS-integrering – använd hookarna
setup()/teardown()och$BATS_TEST_TMPDIRför ren isolering per test
Använd alltid en trap '...' EXIT för att garantera att stubbarna städas bort oavsett testresultat. Håll stubbarna minimala – returnera bara det som skriptet faktiskt tolkar. Filbaserade stubbar är det mest portabla valet för CI-pipelines.
Lär dig Bash med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 22
- Lektioner
- 88
Vanliga frågor
Är lektionen ”Mocka kommandon och stubba externa verktyg” gratis?
Ja – hela texten till ”Mocka kommandon och stubba externa verktyg” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Bemästra Linux-kommandoraden och Bash-skriptning, kan Ni uppgradera till CoddyKit PRO. Kursen i Bemästra Linux-kommandoraden och Bash-skriptning innehåller totalt 4 lektioner.
Vad lär jag mig i ”Mocka kommandon och stubba externa verktyg”?
Ändra PATH och definiera falska binärer för att testa skript utan att påverka riktiga system. Ni övar på Bemästra Linux-kommandoraden och Bash-skriptning med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Bemästra Linux-kommandoraden och Bash-skriptning?
Du behöver inga förkunskaper. Utbildningen i Bemästra Linux-kommandoraden och Bash-skriptning på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.
Hur lång tid tar lektionen ”Mocka kommandon och stubba externa verktyg”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Bemästra Linux-kommandoraden och Bash-skriptning-lektionen?
Ja. Varje Bemästra Linux-kommandoraden och Bash-skriptning-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Enhetstesta funktioner med Bats-core
- Mocka kommandon och stubba externa verktyg
- Testfixturer, temporära miljöer och täckningsgrad
- Kör skaltester i CI-pipelines