Befehle mocken und externe Tools stubben
Überschreiben Sie PATH und definieren Sie gefälschte Binärdateien, um Skripte ohne Zugriff auf echte Systeme zu testen.
Befehle mocken und externe Tools stubben ist eine kostenlose Linux Command Line & Bash Scripting Mastery-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Linux Command Line & Bash Scripting Mastery-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Linux Command Line & Bash Scripting Mastery-Kurs umfasst insgesamt 4 Lektionen.
Warum Befehle in Bash-Tests mocken?
Wenn Sie ein Bash-Skript testen, das curl, aws, git oder ein anderes externes Tool aufruft, stehen Sie vor einem Problem: Echte Aufrufe greifen auf das Netzwerk zu, ändern den Zustand, verursachen Kosten oder schlagen in einer CI-Umgebung einfach fehl, weil die entsprechenden Tools nicht installiert sind.
Mocking bedeutet, den echten Befehl durch einen von Ihnen kontrollierten falschen Befehl zu ersetzen. Ihr falscher Befehl (der Stub) gibt vorhersehbare Ausgaben und Exit-Codes zurück, sodass Ihr Test schnell, isoliert und reproduzierbar ist.
- Kein Netzwerk- oder Cloud-Zugriff erforderlich
- Tests laufen in Millisekunden statt in Sekunden
- Sie können Fehler simulieren, die auf echten Systemen schwer auszulösen sind
- CI-Pipelines bleiben sauber und frei von Abhängigkeiten
Bash bietet dafür einen überraschend einfachen Mechanismus: Platzieren Sie Ihre falsche Binärdatei einfach im $PATH vor der echten.
Funktionsweise der PATH-Suche
Wenn die Shell einen Befehl wie curl ausführt, durchsucht sie die Verzeichnisse in $PATH von links nach rechts und führt den ersten gefundenen Treffer aus.
Das bedeutet: Wenn Sie ein Verzeichnis mit Ihrem eigenen curl-Skript voranstellen, erreicht die Shell niemals /usr/bin/curl.
Das Überschreibungsmuster:
- Erstellen Sie ein temporäres Verzeichnis (Ihr Stub-Binärverzeichnis).
- Schreiben Sie eine ausführbare Datei mit demselben Namen wie der echte Befehl.
- Stellen Sie dieses Verzeichnis dem
PATHvoran. - Führen Sie Ihr zu testendes Skript aus – es ruft Ihren Stub und nicht die echte Binärdatei auf.
- Räumen Sie das temporäre Verzeichnis nach dem Test auf.
Das funktioniert ohne Root-Zugriff, ohne Änderungen an Systemdateien und ohne spezielles Framework.
Ein Stub-Verzeichnis erstellen
Das Standardmuster verwendet mktemp -d, um ein isoliertes temporäres Verzeichnis für Ihre Stubs zu erstellen. Jeder Test oder jede Testsuite erhält ein eigenes Verzeichnis, wodurch Beeinträchtigungen zwischen Tests verhindert werden.
Entfernen Sie das Verzeichnis nach Abschluss des Tests mit rm -rf. Ein trap stellt sicher, dass auch dann aufgeräumt wird, wenn der Test aufgrund eines Fehlers vorzeitig beendet wird.
#!/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."Ihren ersten Stub schreiben
Ein Stub ist einfach eine ausführbare Datei mit demselben Namen wie der Befehl, den Sie ersetzen möchten. Er gibt die Ausgabe aus, die Ihr zu testendes Skript erwartet, und wird mit dem von Ihnen gewählten Code beendet.
Wichtige Regeln für Stubs:
- Die Datei muss ausführbar sein (
chmod +x). - Die Shebang-Zeile (
#!/usr/bin/env bash) ist erforderlich. - Geben Sie die Ausgabe aus, die Ihr echtes Skript verarbeiten würde.
- Verwenden Sie
exit 0für Erfolg und einen Wert ungleich null für simulierte Fehler.
#!/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/versionEin Skript testen, das curl aufruft
Setzen wir nun alles zusammen. Angenommen, Sie haben ein Deployment-Skript, das curl verwendet, um einen Health-Endpunkt zu prüfen, und bei einem nicht fehlerfreien Dienst mit einem Fehler beendet wird. Sie möchten sowohl den Erfolgs- als auch den Fehlerpfad ohne einen echten Server testen.
#!/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"Fehler bei Befehlen simulieren
Eine der wertvollsten Einsatzmöglichkeiten von Stubs ist das Simulieren von Fehlern, die sich mit echten Tools nur schwer reproduzieren lassen – etwa Netzwerk-Timeouts, Berechtigungsfehler, eine volle Festplatte oder eine Remote-API, die mit 500 antwortet.
Um einen Fehler zu simulieren, lassen Sie Ihren Stub einfach mit einem Exit-Code ungleich null beenden. Sie können außerdem wie der echte Befehl in stderr schreiben, sodass die Fehlerbehandlung Ihres Skripts vollständig ausgeführt wird.
#!/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"
fiStub-Aufrufe zur Überprüfung aufzeichnen
Manchmal müssen Sie nicht nur überprüfen, was Ihr Skript ausgibt, sondern auch, wie es ein externes Tool aufgerufen hat – welche Argumente es übergeben hat, wie oft es aufgerufen wurde oder in welcher Reihenfolge. Ein Spy-Stub zeichnet seine Aufrufe in einer Datei auf.
Nach dem Test liest Ihr Test-Harness die Aufzeichnungsdatei ein und überprüft deren Inhalt. So können Sie die Argumente ohne ein spezielles Framework verifizieren.
#!/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"Mehrere Befehle gleichzeitig stubben
Ein echtes Skript ruft häufig mehrere externe Tools auf. Sie können sie alle im selben Verzeichnis STUB_BIN stubben. Jede Stub-Datei ist unabhängig und kann unterschiedliche Ausgaben und Exit-Codes zurückgeben.
Halten Sie Stubs minimal: Geben Sie nur das zurück, was das getestete Skript tatsächlich verarbeitet. Versuchen Sie nicht, jedes Flag zu simulieren – verwenden Sie nur die Teilmenge, die Ihr Skript nutzt.
#!/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"Funktionen als Stubs verwenden (keine Dateien erforderlich)
Für einfache Fälle müssen Sie überhaupt keine Dateien schreiben. Sie können eine Shell-Funktion mit demselben Namen wie der Befehl definieren. Da Funktionen vor der Suche in PATH nach externen Befehlen aufgelöst werden, haben sie automatisch Vorrang.
Dies ist der schnellste Ansatz für Unit-Tests von eingebundenen Skripten. Funktions-Stubs funktionieren jedoch nur innerhalb desselben Shell-Prozesses – in Subshells, die mit explizitem bash -c oder als Hintergrundprozesse gestartet werden, sind sie nicht sichtbar. Verwenden Sie in diesen Fällen den dateibasierten Ansatz.
#!/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"Funktionen in Subshells exportieren
Wenn Ihr getestetes Skript eine Subshell startet (z. B. bash script.sh oder eine Pipeline), werden im übergeordneten Prozess definierte Shell-Funktions-Stubs standardmäßig nicht vererbt. Sie haben zwei Möglichkeiten:
- Verwenden Sie
export -f function_name, um die Funktion zu exportieren – sie wird für untergeordnetebash-Prozesse verfügbar - Oder greifen Sie auf dateibasierte Stubs in einem Verzeichnis
STUB_BINzurück, die über Prozessgrenzen hinweg immer funktionieren
export -f ist elegant, funktioniert aber nur mit bash (nicht mit sh oder anderen Shells). Bevorzugen Sie in CI-Umgebungen mit mehreren Sprachen dateibasierte Stubs.
#!/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)Stubs in ein Test-Framework integrieren (BATS)
Wenn Sie BATS (Bash Automated Testing System) verwenden, gehört die Einrichtung der Stubs in den Hook setup() und der Abbau in teardown(). BATS setzt die Umgebung zwischen den Tests zurück, sodass jeder Test ein neues Stub-Verzeichnis erhält.
BATS-Variablen wie $BATS_TEST_TMPDIR stellen automatisch ein temporäres Verzeichnis pro Test bereit – verwenden Sie dieses anstelle von mktemp -d, um übersichtlicheren Code zu schreiben.
#!/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 ]
}Wissenscheck: Befehle in Bash mocken
Testen Sie Ihr Verständnis von Command-Mocking und Stub-Mustern in Bash.
Eine Entwicklerin oder ein Entwickler schreibt einen Test, der eine Shell-Funktion namens aws definiert, um die echte AWS CLI zu stubben. Der Test läuft direkt im Terminal problemlos, aber wenn die CI-Pipeline das getestete Skript als bash deploy.sh ausführt, wird der Stub ignoriert und der echte Befehl aws aufgerufen.
Was ist die richtige Lösung?
Zusammenfassung: Befehle mocken und externe Tools stubben
Sie haben das vollständige Werkzeugset kennengelernt, um beim Testen von Bash-Skripten echte Befehle durch kontrollierte Fakes zu ersetzen.
Behandelte Kerntechniken:
- PATH voranstellen – Erstellen Sie mit
mktemp -dein VerzeichnisSTUB_BIN, schreiben Sie dort ausführbare Stub-Dateien und stellen Sie das Verzeichnis an den Anfang vonPATH - Exit-Codes von Stubs – Geben Sie für Erfolg
0und für die Simulation bestimmter Fehler (Netzwerkfehler, verweigerte Berechtigungen usw.) Werte ungleich null zurück - Spy-Stubs – Hängen Sie Argumente in der Stub-Datei an eine Protokolldatei an, um zu überprüfen, wie Ihr Skript externe Tools aufgerufen hat
- Mehrere Stubs – Legen Sie mehrere Stub-Dateien im selben
STUB_BINab, um ein ganzes Ökosystem von Abhängigkeiten gleichzeitig zu mocken - Funktions-Stubs – Definieren Sie für Mocking im selben Prozess eine Shell-Funktion mit demselben Namen wie ein Befehl; verwenden Sie
export -f, um untergeordnete Bash-Prozesse zu erreichen - BATS-Integration – Verwenden Sie die Hooks
setup()/teardown()und$BATS_TEST_TMPDIR, um jeden Test sauber zu isolieren
Verwenden Sie immer ein trap '...' EXIT, um die Bereinigung der Stubs unabhängig vom Testergebnis zu garantieren. Halten Sie Stubs minimal – geben Sie nur das zurück, was Ihr Skript tatsächlich verarbeitet. Dateibasierte Stubs sind die portabelste Wahl für CI-Pipelines.
Häufig gestellte Fragen
Ist die Lektion „Befehle mocken und externe Tools stubben“ kostenlos?
Ja — der vollständige Text von „Befehle mocken und externe Tools stubben“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Linux Command Line & Bash Scripting Mastery-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Linux Command Line & Bash Scripting Mastery-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Befehle mocken und externe Tools stubben“?
Überschreiben Sie PATH und definieren Sie gefälschte Binärdateien, um Skripte ohne Zugriff auf echte Systeme zu testen. Du übst Linux Command Line & Bash Scripting Mastery mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Linux Command Line & Bash Scripting Mastery zu starten?
Keine Vorkenntnisse erforderlich. Linux Command Line & Bash Scripting Mastery auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.
Wie lange dauert die Lektion „Befehle mocken und externe Tools stubben“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Linux Command Line & Bash Scripting Mastery-Lektion Code schreiben und ausführen?
Ja. Jede Linux Command Line & Bash Scripting Mastery-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Funktionen mit Bats-core per Unit-Test prüfen
- Befehle mocken und externe Tools stubben
- Fixtures, temporäre Umgebungen und Coverage
- Shell-Tests in CI-Pipelines ausführen