Linux-komentorivin ja Bash-komentosarjojen hallinta · Oppitunti

Komentojen mallintaminen ja ulkoisten työkalujen korvaaminen

Ohita PATH ja määritä valekäännösohjelmat, jotta voit testata skriptejä koskematta oikeisiin järjestelmiin.

Oppitunti 2/413 vaihetta

Komentojen mallintaminen ja ulkoisten työkalujen korvaaminen on ilmainen Linux-komentorivin ja Bash-komentosarjojen hallinta-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Linux-komentorivin ja Bash-komentosarjojen hallinta-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Linux-komentorivin ja Bash-komentosarjojen hallinta-kurssilla on yhteensä 4 oppituntia.

Miksi komentoja mockataan Bash-testeissä?

Kun testaatte Bash-skriptiä, joka kutsuu komentoja curl, aws, git tai jotakin muuta ulkoista työkalua, kohtaatte ongelman: oikeat kutsut käyttävät verkkoa, muuttavat tilaa, maksavat rahaa tai yksinkertaisesti epäonnistuvat CI-ympäristössä, johon kyseisiä työkaluja ei ole asennettu.

Mockauksella tarkoitetaan oikean komennon korvaamista itse hallitsemallanne valekomennolla. Valekomento eli stub palauttaa ennakoitavan tulosteen ja paluuarvon, joten testi on nopea, eristetty ja toistettavissa.

  • Verkko- tai pilvipalveluyhteyttä ei tarvita
  • Testit suoritetaan millisekunneissa sekuntien sijaan
  • Voitte simuloida virheitä, joita on vaikea saada aikaan oikeissa järjestelmissä
  • CI-putket pysyvät siisteinä ja riippumattomina ulkoisista riippuvuuksista

Bash tarjoaa tähän yllättävän yksinkertaisen mekanismin: sijoittakaa vain valebinääri $PATH-muuttujassa ennen oikeaa binääriä.

Miten PATH-haku toimii

Kun shell suorittaa esimerkiksi komennon curl, se etsii $PATH-muuttujan jokaisesta hakemistosta vasemmalta oikealle ja suorittaa ensimmäisen löytämänsä vastineen.

Tämä tarkoittaa, että jos lisäätte etusijalle hakemiston, joka sisältää oman curl-skriptinne, shell ei koskaan päädy tiedostoon /usr/bin/curl.

Ohitusmalli:

  1. Luokaa väliaikainen hakemisto (stub-binäärihakemisto)
  2. Kirjoittakaa suoritettava valetiedosto, jolla on sama nimi kuin oikealla komennolla
  3. Lisätkää kyseinen hakemisto PATH-muuttujan alkuun
  4. Suorittakaa testattava skripti — se kutsuu valettanne, ei oikeaa binääriä
  5. Siivotkaa väliaikainen hakemisto testin jälkeen

Tämä toimii ilman pääkäyttäjän oikeuksia, järjestelmätiedostojen muokkaamista ja erityistä kehystä.

Stub-hakemiston luominen

Vakiintuneessa toimintamallissa eristetty väliaikainen hakemisto valeita varten luodaan komennolla mktemp -d. Jokainen testi tai testisarja saa oman hakemistonsa, mikä estää testien välisen sotkeutumisen.

Poistakaa hakemisto testin päätyttyä komennolla rm -rf. trap-komennon avulla siivous tehdään myös silloin, kun testi päättyy virheeseen ennenaikaisesti.

#!/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."

Ensimmäisen stubbinne kirjoittaminen

Stub on yksinkertaisesti suoritettava tiedosto, jolla on sama nimi kuin korvattavalla komennolla. Se tulostaa sen tulosteen, jota testattava skripti odottaa, ja päättyy valitsemallanne koodilla.

Stubien keskeiset säännöt:

  • Tiedoston on oltava suoritettava (chmod +x)
  • Shebang-rivi (#!/usr/bin/env bash) vaaditaan
  • Tulostakaa tuloste, jonka oikea skriptinne käsittelisi
  • Käyttäkää onnistumiseen komentoa exit 0 ja simuloituihin virheisiin nollasta poikkeavaa arvoa
#!/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

curl-komentoa kutsuvan skriptin testaaminen

Kootaan nyt kaikki yhteen. Oletetaan, että teillä on käyttöönottoskripti, joka kutsuu curl-komentoa palvelun terveystilan tarkistamiseen ja päättyy virheeseen, jos palvelu ei ole kunnossa. Haluatte testata sekä onnistuvan että epäonnistuvan tilanteen ilman oikeaa palvelinta.

#!/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"

Komentojen toimintahäiriöiden simulointi

Yksi stubien arvokkaimmista käyttötavoista on sellaisten virhetilanteiden simulointi, joita on vaikea toistaa oikeilla työkaluilla — verkkoyhteyden aikakatkaisut, käyttöoikeusvirheet, täysi levy tai etä-API:n palauttama 500-virhe.

Voitte simuloida virheen yksinkertaisesti määrittämällä stubin päättymään nollasta poikkeavaan koodiin. Voitte myös kirjoittaa stderr-virtaan täsmälleen samalla tavalla kuin oikea komento kirjoittaisi, jolloin skriptinne virheenkäsittely tulee testattua kattavasti.

#!/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

Stubikutsujen tallentaminen tarkistamista varten

Joskus on tarpeen tarkistaa paitsi mitä skriptinne tulostaa, myös miten se kutsui ulkoista työkalua — mitä argumentteja se välitti, kuinka monta kertaa sitä kutsuttiin tai missä järjestyksessä kutsut tehtiin. Vakoilustubi tallentaa kutsunsa tiedostoon.

Testin jälkeen testikehys lukee tallennetiedoston ja tarkistaa sen sisällön. Näin saatte argumenttitason tarkistukset ilman erillistä kehystä.

#!/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"

Useiden komentojen stubbaaminen kerralla

Oikea skripti kutsuu usein useita ulkoisia työkaluja. Voitte stubata ne kaikki samaan STUB_BIN-hakemistoon. Jokainen stubitiedosto on itsenäinen, ja se voi palauttaa eri tulosteita ja päättymiskoodeja.

Pitäkää stubit pieninä: palauttakaa vain se, minkä testattava skripti todella jäsentää. Älkää yrittäkö simuloida jokaista valitsinta — käyttäkää vain skriptinne tarvitsemaa osajoukkoa.

#!/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"

Funktioiden käyttäminen stubina (tiedostoja ei tarvita)

Yksinkertaisissa tapauksissa tiedostoja ei tarvitse luoda lainkaan. Voitte määrittää shell-funktion, jolla on sama nimi kuin komennolla. Koska funktiot ratkaistaan ennen ulkoisten komentojen etsimistä PATH-muuttujasta, ne saavat automaattisesti etusijan.

Tämä on nopein tapa testata yksikkötasolla lähdekoodina ladattuja skriptejä. Funktiostubit toimivat kuitenkin vain saman shell-prosessin sisällä — ne eivät näy alishelleille, jotka käynnistetään eksplisiittisellä komennolla bash -c, eivätkä taustaprosesseille. Käyttäkää tällaisissa tapauksissa tiedostopohjaista lähestymistapaa.

#!/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"

Funktioiden vieminen alishelleihin

Kun testattava skriptinne käynnistää alishellin (esimerkiksi komennolla bash script.sh tai putkella), emo-prosessissa määritetyt shell-funktiostubit eivät oletusarvoisesti periydy. Teillä on kaksi vaihtoehtoa:

  • Viekää funktio komennolla export -f function_name — tällöin se on käytettävissä lapsiprosesseissa, jotka käyttävät bash-komentoa
  • Siirtykää tiedostopohjaisiin stubihin STUB_BIN-hakemistossa; ne toimivat aina prosessirajojen yli

export -f on elegantti ratkaisu, mutta se toimii vain bash-shellissä (ei sh-shellissä tai muissa shelleissä). Monikielisissä CI-ympäristöissä tiedostopohjaiset stubit ovat suositeltava vaihtoehto.

#!/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)

Stubien integrointi testikehykseen (BATS)

Kun käytätte BATS-järjestelmää (Bash Automated Testing System), stubien valmistelu kuuluu setup()-koukkuun ja purkaminen teardown()-koukkuun. BATS palauttaa ympäristön alkutilaan testien välillä, joten jokainen testi saa uuden stubihakemiston.

BATS-muuttujat, kuten $BATS_TEST_TMPDIR, tarjoavat automaattisesti testi­kohtaisen väliaikaishakemiston — käyttäkää sitä komennon mktemp -d sijaan, jotta koodista tulee siistimpää.

#!/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 ]
}

Tietotesti: komentojen mockaaminen Bashissa

Testatkaa, kuinka hyvin ymmärrätte komentojen mockaamisen ja stubimallit Bashissa.

Kehittäjä kirjoittaa testin, joka määrittää aws-nimisen shell-funktion korvaamaan oikean AWS CLI:n. Testi toimii suoraan terminaalissa, mutta kun CI-putki suorittaa testattavan skriptin komennolla bash deploy.sh, stubi ohitetaan ja oikea aws-komento suoritetaan.

Mikä korjaus on oikea?

Kertaus: komentojen mockaaminen ja ulkoisten työkalujen stubbaaminen

Olette oppineet kattavan työkalupakin oikeiden komentojen korvaamiseen hallituilla korvikkeilla Bash-skriptien testauksen aikana.

Keskeiset käsitellyt tekniikat:

  • PATH-muuttujan alkuun lisääminen — luokaa komennolla mktemp -d STUB_BIN-hakemisto, kirjoittakaa sinne suoritettavia stubitiedostoja ja lisätkää hakemisto PATH-muuttujan alkuun
  • Stubien päättymiskoodit — palauttakaa onnistumisesta 0 ja käyttäkää nollasta poikkeavia arvoja tiettyjen virheiden (verkkovirheet, käyttö estetty jne.) simulointiin
  • Vakoilustubit — lisätkää argumentit stubin sisällä olevaan lokitiedostoon, jotta voitte tarkistaa, miten skriptinne kutsui ulkoisia työkaluja
  • Useat stubit — sijoittakaa useita stubitiedostoja samaan STUB_BIN-hakemistoon, jotta voitte mockata kokonaisen riippuvuusekosysteemin kerralla
  • Funktiostubit — määrittäkää komennon niminen shell-funktio saman prosessin sisäistä mockaamista varten; käyttäkää komentoa export -f, jotta funktio on käytettävissä lapsiprosesseissa, jotka käyttävät Bashia
  • BATS-integraatio — käyttäkää setup()- ja teardown()-koukkuja sekä muuttujaa $BATS_TEST_TMPDIR testikohtaiseen eristykseen

Käyttäkää aina muotoa trap '...' EXIT varmistaaksenne stubien siivouksen testin tuloksesta riippumatta. Pitäkää stubit pieninä — palauttakaa vain se, minkä skriptinne todella jäsentää. Tiedostopohjaiset stubit ovat CI-putkissa siirrettävin vaihtoehto.

Aloita maksutta

Opi Bash tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
22
Oppitunnit
88

Usein kysytyt kysymykset

Onko oppitunti ”Komentojen mallintaminen ja ulkoisten työkalujen korvaaminen” ilmainen?

Kyllä – oppitunnin ”Komentojen mallintaminen ja ulkoisten työkalujen korvaaminen” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Linux-komentorivin ja Bash-komentosarjojen hallinta-kurssin, päivitä CoddyKit PROhon. Linux-komentorivin ja Bash-komentosarjojen hallinta-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Komentojen mallintaminen ja ulkoisten työkalujen korvaaminen”?

Ohita PATH ja määritä valekäännösohjelmat, jotta voit testata skriptejä koskematta oikeisiin järjestelmiin. Harjoittelet Linux-komentorivin ja Bash-komentosarjojen hallinta-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Linux-komentorivin ja Bash-komentosarjojen hallinta-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Linux-komentorivin ja Bash-komentosarjojen hallinta-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.

Kuinka kauan ”Komentojen mallintaminen ja ulkoisten työkalujen korvaaminen”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Linux-komentorivin ja Bash-komentosarjojen hallinta-oppitunnilla?

Kyllä. Jokainen Linux-komentorivin ja Bash-komentosarjojen hallinta-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Funktioiden yksikkötestaus Bats-corella
  2. Komentojen mallintaminen ja ulkoisten työkalujen korvaaminen
  3. Testiaineistot, väliaikaisympäristöt ja kattavuus
  4. Shell-testien suorittaminen CI-putkissa
← Takaisin: Linux-komentorivin ja Bash-komentosarjojen hallinta