少し修正するたびに全パターンを手動で確認するのは、スクリプトが複雑になるほど現実的ではありません。バグを気づかずに本番環境へ持ち込んでしまったり、修正のたびに既存の動作を壊していないか不安になったりすることもあるでしょう。
この記事では、Bash製シェルスクリプト向けテストフレームワーク bats-core を使って、ユニットテストを自動実行する方法を解説します。
インストールから基本的なテストの書き方、前処理・後処理(setup/teardown)、モック関数の定義、GitHub ActionsでのCI設定まで、実際のコードを交えて説明します。
動作確認環境:Ubuntu 24.04 LTS / RHEL 9.4(Rocky Linux 9.4 でも確認済み)
この記事のポイント
・bats-coreはBashスクリプト専用テストフレームワーク
・@testブロックでテストケースを簡潔に定義できる
・setup/teardownで前後処理を各テストから分離できる
・GitHub ActionsでCI自動テストの実行が可能
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
bats-coreとは?シェルスクリプト用テストフレームワークの概要
bats-core(Bash Automated Testing System)は、Bashシェルスクリプト向けのユニットテストフレームワークです。2011年に公開されたオリジナルの
bats をコミュニティがフォークして保守しているのが bats-core であり、現在のメンテナンスはこちらに移っています。テスト結果はTAP(Test Anything Protocol)形式で出力されるため、CI/CDツールとの統合も容易です。また、テストファイルは通常のシェルスクリプトに近い構文で書けるため、学習コストが低いのも利点です。
Linuxの基本コマンド操作に慣れていることを前提にしています。コマンドラインの基礎を確認したい方はLinux 基本コマンドの解説もあわせてご参照ください。
bats-core が向いているケース:
・シェルスクリプトの動作をユニットテストで自動検証したい
・スクリプト修正後のリグレッションを防ぎたい
・GitHub ActionsなどのCI環境でテストを自動実行したい
bats-coreのインストール方法(Linux・macOS対応)
1. Ubuntu / Debian へのインストール
Ubuntu 22.04 以降であれば、apt でそのまま導入できます。# Ubuntu / Debian の場合 sudo apt update sudo apt install bats
bats --version # Bats 1.10.0 などのように表示されれば成功
2. RHEL 9 / Rocky Linux 9 へのインストール
RHEL 9 系のデフォルトリポジトリには含まれていないため、GitHubから直接取得します。# bats-core のソースを取得してインストール git clone https://github.com/bats-core/bats-core.git cd bats-core sudo ./install.sh /usr/local
# インストール確認 bats --version # Bats 1.11.0 などと表示されれば完了
3. macOS へのインストール
Homebrew が入っていれば一行で完了します。brew install bats-core
最初のbatsテストを書く|基本構文とアサーション
1. テストファイルの作成
bats のテストファイルは拡張子.bats を使います。まず、テスト対象のスクリプトを作成します。# テスト対象スクリプト: greet.sh #!/usr/bin/env bash name="${1:-world}" echo "Hello, ${name}!"
tests/ ディレクトリ以下に作成します。# テストファイル: tests/greet_test.bats #!/usr/bin/env bats @test "デフォルト引数でHello, world!と出力される" { run ./greet.sh [ "$status" -eq 0 ] [ "$output" = "Hello, world!" ] } @test "引数を渡すと名前付き挨拶が返る" { run ./greet.sh "Linux" [ "$status" -eq 0 ] [ "$output" = "Hello, Linux!" ] }
2. テストの実行と出力の確認
bats tests/greet_test.bats
v デフォルト引数でHello, world!と出力される v 引数を渡すと名前付き挨拶が返る 2 tests, 0 failures
3. 主なアサーション変数
run コマンドを使ってスクリプトを実行すると、以下の変数に結果が格納されます。・
$status :コマンドの終了コード(0 が正常)・
$output :標準出力の全文字列・
$lines[n] :n行目の出力(0始まり)実践的なテストケースの作り方|前処理・後処理・モック
1. setup と teardown で共通処理を分離する
テストごとに一時ディレクトリの作成・削除が必要な場合、setup() と teardown() を定義します。#!/usr/bin/env bats setup() { # 各テストの前に実行される TEST_DIR="$(mktemp -d)" } teardown() { # 各テストの後に必ず実行される rm -rf "${TEST_DIR}" } @test "一時ディレクトリにファイルを作成できる" { touch "${TEST_DIR}/sample.txt" [ -f "${TEST_DIR}/sample.txt" ] }
teardown() はテストが失敗した場合でも実行されるため、後片付けの漏れを防げます。ファイル全体の前後処理(テスト群の最初と最後に1回だけ実行)が必要な場合は
setup_file() と teardown_file() を使います。2. 関数のモックで外部依存を切り離す
APIを呼び出すスクリプトをテストする際、実際のHTTP通信を避けるためにモック関数で curl を差し替えます。#!/usr/bin/env bats # curl をモック関数で上書きする function curl() { echo '{"status":"ok","code":200}' } export -f curl @test "APIが正常応答を返したとき成功する" { run ./api_client.sh [ "$status" -eq 0 ] [[ "$output" =~ "ok" ]] }
export -f 関数名 でサブシェルへ関数をエクスポートできます。batsは run の内部でサブシェルを使うため、このエクスポートが必要です。シェルスクリプトの品質保証を体系的に学びたい方は、シェルスクリプト講座でテスト戦略を含めた学習もできます。
GitHub ActionsでCI自動実行する設定
リポジトリに以下のワークフローファイルを配置するだけで、プッシュのたびに bats テストが自動実行されます。# .github/workflows/shell-test.yml name: Shell Script Tests on: push: branches: [main] pull_request: branches: [main] jobs: bats-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: bats-coreをインストールする run: | git clone https://github.com/bats-core/bats-core.git cd bats-core sudo ./install.sh /usr/local - name: テストを実行する run: bats tests/
v デフォルト引数でHello, world!と出力される v 引数を渡すと名前付き挨拶が返る v APIが正常応答を返したとき成功する 3 tests, 0 failures
テスト設計のベストプラクティス|よくあるエラーと注意点
1. テストファイルの命名規則
bats はディレクトリを指定すると*.bats パターンのファイルを全件実行します。命名は以下のいずれかで統一するとわかりやすくなります。・テスト対象ファイル名に
_test を付ける:greet_test.bats・
test_ プレフィックスを付ける:test_greet.bats2. 1テスト1アサーションを意識する
1つの@test ブロックに複数の確認を詰め込むと、どのアサーションが失敗したか特定しにくくなります。テスト名を明確にしつつ、確認観点ごとにブロックを分けましょう。3. run のサブシェル動作に注意する
run コマンドはサブシェル内でコマンドを実行します。そのため、テスト対象スクリプト内で cd したカレントディレクトリの変更はテスト側に影響しません。パス依存のスクリプトをテストする場合は、
BATS_TEST_DIRNAME(テストファイルのディレクトリパス)を使って絶対パスを指定するのが確実です。@test "絶対パスでスクリプトを指定する" { run "${BATS_TEST_DIRNAME}/../greet.sh" "bats" [ "$output" = "Hello, bats!" ] }
4. エラー出力(stderr)を確認する
run のデフォルトでは標準エラー出力(stderr)は $output に含まれません。bats 1.5以降では run --separate-stderr フラグで分離できます。@test "エラーメッセージが stderr に出力される" { run --separate-stderr ./error_script.sh [ "$status" -ne 0 ] [[ "$stderr" =~ "ERROR:" ]] }
まとめ|shellcheckとの使い分けと品質保証の全体像
シェルスクリプトの品質保証には静的解析ツール shellcheck と bats-core を組み合わせるのが現場での定番パターンです。それぞれの役割は明確に分かれています。| ツール | 役割 | 検出できること |
|---|---|---|
| shellcheck | 静的解析 | 構文エラー・スタイル・よくあるバグパターン |
| bats-core | 動的テスト | 実行時の動作・出力・終了コードの正確性 |
| やりたいこと | コマンド・記述 |
|---|---|
| テストファイルを実行する | bats test_file.bats |
| ディレクトリ内の全テストを実行する | bats tests/ |
| 終了コードを確認する | [ "$status" -eq 0 ] |
| 出力内容を確認する | [ "$output" = "期待値" ] |
| 出力に文字列が含まれるか確認する | [[ "$output" =~ "部分文字列" ]] |
| 前処理を定義する | setup() { ... } |
| 後処理を定義する | teardown() { ... } |
| 関数をモックする | function コマンド名() { ... }; export -f コマンド名 |
シェルスクリプトをさらに体系的に学びたい方は、シェルスクリプト講座をご覧ください。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら
- 前のページへ:シェルスクリプトの設定を外部ファイル化する設計|sourceと.envで環境別に切り替える方法
- この記事の属するカテゴリ:シェルスクリプトへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。
登録無料・いつでも解除できます