bats-coreでシェルスクリプトをテストする方法|ユニットテストの書き方とCI自動実行

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)シェルスクリプト > bats-coreでシェルスクリプトをテストする方法|ユニットテストの書き方とCI自動実行
「シェルスクリプトを書いたあと、テストは毎回手動で実行しているだけになっていませんか。」
少し修正するたびに全パターンを手動で確認するのは、スクリプトが複雑になるほど現実的ではありません。バグを気づかずに本番環境へ持ち込んでしまったり、修正のたびに既存の動作を壊していないか不安になったりすることもあるでしょう。

この記事では、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自動テストの実行が可能


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

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/

上記の設定で GitHub Actions のCI実行ログには以下のように表示されます。

v デフォルト引数でHello, world!と出力される v 引数を渡すと名前付き挨拶が返る v APIが正常応答を返したとき成功する 3 tests, 0 failures

失敗したテストがあると終了コード 1 が返るため、CIが自動でジョブをNG判定し、マージをブロックします。

テスト設計のベストプラクティス|よくあるエラーと注意点

1. テストファイルの命名規則

bats はディレクトリを指定すると *.bats パターンのファイルを全件実行します。命名は以下のいずれかで統一するとわかりやすくなります。

・テスト対象ファイル名に _test を付ける:greet_test.bats
test_ プレフィックスを付ける:test_greet.bats

2. 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-core で検証できる主な操作をまとめます。
やりたいこと コマンド・記述
テストファイルを実行する bats test_file.bats
ディレクトリ内の全テストを実行する bats tests/
終了コードを確認する [ "$status" -eq 0 ]
出力内容を確認する [ "$output" = "期待値" ]
出力に文字列が含まれるか確認する [[ "$output" =~ "部分文字列" ]]
前処理を定義する setup() { ... }
後処理を定義する teardown() { ... }
関数をモックする function コマンド名() { ... }; export -f コマンド名
CI自動化まで設定しておくと、スクリプトの変更がプッシュされるたびにテストが走るため、リグレッションを早期に発見できます。shellcheck と bats-core を両輪にした品質保証フローを、ぜひ現場のシェルスクリプト開発に取り入れてみてください。

シェルスクリプトをさらに体系的に学びたい方は、シェルスクリプト講座をご覧ください。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。