0Pricing
Linux Command Line & Bash Scripting Mastery · 강의

명령 모킹 및 외부 도구 스텁 처리

PATH를 재정의하고 가짜 바이너리를 정의하여 실제 시스템에 영향을 주지 않고 스크립트를 테스트합니다.

명령 모킹 및 외부 도구 스텁 처리은(는) CoddyKit의 무료 Linux Command Line & Bash Scripting Mastery 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Linux Command Line & Bash Scripting Mastery 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Linux Command Line & Bash Scripting Mastery 강의에는 총 4개의 강의가 포함되어 있습니다.

Bash 테스트에서 명령을 모의 처리하는 이유

curl, aws, git 또는 외부 도구를 호출하는 Bash 스크립트를 테스트할 때 문제가 생깁니다. 실제 호출은 네트워크에 연결하고, 상태를 변경하고, 비용을 발생시키거나, 해당 도구가 설치되지 않은 CI 환경에서 단순히 실패할 수 있습니다.

모의 처리란 실제 명령을 여러분이 제어하는 가짜 명령으로 바꾸는 것을 뜻합니다. 가짜 명령(스텁)은 예측 가능한 출력과 종료 코드를 반환하므로 테스트가 빠르고, 독립적이며, 재현 가능합니다.

  • 네트워크나 클라우드 액세스가 필요하지 않습니다.
  • 테스트가 수 초가 아니라 수 밀리초 안에 실행됩니다.
  • 실제 시스템에서는 유발하기 어려운 오류를 시뮬레이션할 수 있습니다.
  • CI 파이프라인을 깔끔하게 유지하고 종속성 없이 실행할 수 있습니다.

Bash는 이를 수행하는 놀라울 정도로 간단한 메커니즘을 제공합니다. 실제 바이너리보다 $PATH에서 앞선 위치에 가짜 바이너리를 두기만 하면 됩니다.

PATH 조회 작동 방식

셸이 curl 같은 명령을 실행하면 $PATH의 각 디렉터리를 왼쪽에서 오른쪽으로 검색하고, 처음 발견한 일치 항목을 실행합니다.

따라서 자체 curl 스크립트가 들어 있는 디렉터리를 앞에 추가하면 셸은 /usr/bin/curl까지 도달하지 않습니다.

재정의 패턴:

  1. 임시 디렉터리(여러분의 스텁 바이너리 디렉터리)를 만듭니다.
  2. 실제 명령과 같은 이름의 가짜 실행 파일을 작성합니다.
  3. 해당 디렉터리를 PATH 앞에 추가합니다.
  4. 테스트할 스크립트를 실행합니다. 스크립트는 실제 바이너리가 아니라 여러분의 스텁을 호출합니다.
  5. 테스트 후 임시 디렉터리를 정리합니다.

이 방법은 루트 액세스나 시스템 파일 수정, 특별한 프레임워크 없이 작동합니다.

스텁 디렉터리 만들기

표준 패턴에서는 mktemp -d를 사용해 스텁을 위한 격리된 임시 디렉터리를 만듭니다. 각 테스트 또는 테스트 모음이 자체 디렉터리를 가지므로 테스트 간 오염을 방지할 수 있습니다.

테스트가 완료되면 rm -rf로 디렉터리를 제거하세요. trap을 사용하면 오류로 인해 테스트가 일찍 종료되는 경우에도 정리가 실행됩니다.

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

첫 번째 스텁 작성하기

스텁은 바꾸려는 명령과 같은 이름을 가진 실행 파일일 뿐입니다. 테스트할 스크립트가 기대하는 출력이 무엇이든 출력하고, 여러분이 선택한 코드로 종료합니다.

스텁의 주요 규칙은 다음과 같습니다.

  • 파일은 실행 가능해야 합니다(chmod +x).
  • 셔뱅 줄(#!/usr/bin/env bash)이 필요합니다.
  • 실제 스크립트가 해석할 출력을 에코합니다.
  • 성공에는 exit 0을 사용하고, 시뮬레이션한 실패에는 0이 아닌 값을 사용합니다.
#!/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을 호출하는 스크립트 테스트하기

이제 지금까지의 내용을 하나로 묶어 보겠습니다. 상태 확인 엔드포인트를 확인하기 위해 curl을 호출한 다음 서비스가 정상 상태가 아니면 오류와 함께 종료하는 배포 스크립트가 있다고 가정해 보세요. 실제 서버 없이 정상 경로와 실패 경로를 모두 테스트하려고 합니다.

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

명령 실패 시뮬레이션

스텁의 가장 유용한 용도 중 하나는 실제 도구로 재현하기 어려운 실패를 시뮬레이션하는 것입니다. 네트워크 시간 초과, 권한 오류, 디스크 가득 참, 원격 API의 500 응답 등이 그 예입니다.

실패를 시뮬레이션하려면 스텁이 0이 아닌 코드로 종료되게 하면 됩니다. 실제 명령이 출력하는 것과 정확히 같은 방식으로 stderr에 쓸 수도 있으므로, 스크립트의 오류 처리가 완전히 실행됩니다.

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

검증을 위한 스텁 호출 기록

때로는 스크립트가 무엇을 출력했는지뿐 아니라 외부 도구를 어떻게 호출했는지도 확인해야 합니다. 전달한 인수, 호출 횟수, 호출 순서 등을 확인하는 경우입니다. 스파이 스텁은 호출 기록을 파일에 저장합니다.

테스트가 끝나면 테스트 도구가 기록 파일을 읽고 그 내용에 대해 검증합니다. 따라서 별도의 프레임워크 없이도 인수 수준의 검증을 수행할 수 있습니다.

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

여러 명령을 한 번에 스텁 처리하기

실제 스크립트는 외부 도구를 여러 개 호출하는 경우가 많습니다. 같은 STUB_BIN 디렉터리에서 모두 스텁 처리할 수 있습니다. 각 스텁 파일은 서로 독립적이며 서로 다른 출력과 종료 코드를 반환할 수 있습니다.

스텁은 최소한으로 유지하십시오. 테스트 대상 스크립트가 실제로 구문 분석하는 것만 반환해야 합니다. 모든 플래그를 시뮬레이션하려 하지 말고 스크립트가 사용하는 일부만 처리하십시오.

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

함수를 스텁으로 사용하기(파일 불필요)

간단한 경우에는 파일을 전혀 작성할 필요가 없습니다. 명령과 같은 이름의 셸 함수를 정의하면 됩니다. 함수는 외부 PATH 조회보다 먼저 확인되므로 자동으로 우선 적용됩니다.

이는 소스 코드를 불러오는 스크립트를 단위 테스트할 때 가장 빠른 방법입니다. 하지만 함수 스텁은 같은 셸 프로세스 안에서만 작동합니다. 명시적인 bash -c로 생성한 하위 셸이나 백그라운드 프로세스에서는 보이지 않습니다. 그런 경우에는 파일 기반 방식을 사용하십시오.

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

하위 셸로 함수 내보내기

테스트 대상 스크립트가 하위 셸을 실행할 때(예: bash script.sh 또는 파이프라인), 부모 셸에서 정의한 셸 함수 스텁은 기본적으로 상속되지 않습니다. 다음 두 가지 방법이 있습니다.

  • export -f function_name을 사용해 함수를 내보내면 하위 bash 프로세스에서 사용할 수 있습니다.
  • 또는 항상 프로세스 경계를 넘어 작동하는 STUB_BIN 디렉터리의 파일 기반 스텁으로 대체할 수 있습니다.

export -f는 간결하지만 bash에서만 작동하며(sh나 다른 셸에서는 작동하지 않음), 여러 언어가 섞인 CI 환경에서는 파일 기반 스텁을 우선 사용하십시오.

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

테스트 프레임워크와 스텁 통합하기(BATS)

BATS(Bash 자동화 테스트 시스템)를 사용할 때는 스텁 설정을 setup() 훅에, 정리 작업을 teardown()에 넣습니다. BATS는 테스트 사이에 환경을 초기화하므로 각 테스트가 새로운 스텁 디렉터리를 사용하게 됩니다.

$BATS_TEST_TMPDIR 같은 BATS 변수는 테스트마다 사용할 임시 디렉터리를 자동으로 제공합니다. 더 깔끔한 코드를 위해 mktemp -d 대신 사용하십시오.

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

지식 확인: Bash에서 명령 모킹하기

Bash에서 명령을 모킹하고 스텁 패턴을 사용하는 방법을 제대로 이해했는지 확인해 보십시오.

한 개발자가 실제 AWS CLI를 스텁 처리하기 위해 aws라는 셸 함수를 정의하는 테스트를 작성했습니다. 터미널에서 직접 실행하면 테스트가 정상적으로 작동하지만, CI 파이프라인이 테스트 대상 스크립트를 bash deploy.sh로 실행하면 스텁이 무시되고 실제 aws 명령이 호출됩니다.

올바른 해결 방법은 무엇입니까?

복습: 명령 모킹과 외부 도구 스텁 처리

Bash 스크립트 테스트 중에 실제 명령을 제어 가능한 가짜 명령으로 대체하는 데 필요한 전체 도구 모음을 학습했습니다.

다룬 핵심 기법:

  • PATH 앞에 디렉터리 추가 — mktemp -d로 STUB_BIN 디렉터리를 만들고, 그 안에 실행 가능한 스텁 파일을 작성한 다음 디렉터리를 PATH 앞에 추가합니다.
  • 스텁 종료 코드 — 성공할 때는 0을 반환하고, 네트워크 오류나 권한 거부 같은 특정 실패를 시뮬레이션할 때는 0이 아닌 값을 반환합니다.
  • 스파이 스텁 — 스크립트가 외부 도구를 어떻게 호출했는지 검증할 수 있도록 스텁 내부의 로그 파일에 인수를 추가합니다.
  • 여러 스텁 — 여러 스텁 파일을 같은 STUB_BIN에 배치하여 전체 의존 생태계를 한 번에 모킹합니다.
  • 함수 스텁 — 같은 프로세스에서 모킹할 수 있도록 명령과 같은 이름의 셸 함수를 정의하고, 하위 bash 프로세스까지 적용하려면 export -f를 사용합니다.
  • BATS 통합 — 깨끗한 테스트별 격리를 위해 setup()/teardown() 훅과 $BATS_TEST_TMPDIR를 사용합니다.

테스트 결과와 관계없이 스텁을 정리하려면 항상 trap '...' EXIT을 사용하십시오. 스텁은 최소한으로 유지하고, 스크립트가 실제로 구문 분석하는 것만 반환하십시오. CI 파이프라인에서는 파일 기반 스텁이 가장 이식성이 높은 선택입니다.

자주 묻는 질문

“명령 모킹 및 외부 도구 스텁 처리” 강의는 무료인가요?

네 — “명령 모킹 및 외부 도구 스텁 처리” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Linux Command Line & Bash Scripting Mastery 강의 전체를 잠금 해제할 수 있습니다. Linux Command Line & Bash Scripting Mastery 강의에는 총 4개의 강의가 포함되어 있습니다.

“명령 모킹 및 외부 도구 스텁 처리”에서 뭘 배우나요?

PATH를 재정의하고 가짜 바이너리를 정의하여 실제 시스템에 영향을 주지 않고 스크립트를 테스트합니다. 브라우저에서 직접 실행하는 실습 코드로 Linux Command Line & Bash Scripting Mastery을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Linux Command Line & Bash Scripting Mastery을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Linux Command Line & Bash Scripting Mastery은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“명령 모킹 및 외부 도구 스텁 처리” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Linux Command Line & Bash Scripting Mastery 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Linux Command Line & Bash Scripting Mastery 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. Bats-core로 함수 단위 테스트
  2. 명령 모킹 및 외부 도구 스텁 처리
  3. 테스트 픽스처, 임시 환경 및 커버리지
  4. CI 파이프라인에서 셸 테스트 실행
← Linux Command Line & Bash Scripting Mastery(으)로 돌아가기