シェルスクリプトのテストフレームワーク Bats を試してみた.
たまにコントリビュートをしている Amazon ECS (Elastic Container Service) のデプロイツール ecs-deploy のテストコードで Bats が使われているので,少し書いたことがあり,もっと詳しく調べてみようと思った.
Bats は現在もメンテナンスされている
もともとの Bats は sstephenson/bats
にあり,現在は bats-core/bats-core
に移っている.以下の Issue などを読むと,コミュニティの動きがわかる.
インストール
Bats は様々なインストール方法がある.まず,用意されている install.sh
を試してみた.
$ git clone git@github.com:bats-core/bats-core.git $ cd bats-core $ sudo ./install.sh /usr/local $ which bats /usr/local/bin/bats
Mac の場合は brew でもインストールできる.
$ brew install bats
他にも,サードパーティだけど,npm でもインストールできる.
サンプルコード
まず,README に以下のサンプルコード addition.bats
が載っているので実行してみた.テストコードとしては bc
で加算をするテストと,dc
で逆ポーランド記法の計算をするテストコードが書かれている.
#!/usr/bin/env bats @test "addition using bc" { result="$(echo 2+2 | bc)" [ "$result" -eq 4 ] } @test "addition using dc" { result="$(echo 2 2+p | dc)" [ "$result" -eq 4 ] }
実行をすると,以下のような出力となる.なお,ターミナルで実行する場合は --pretty
オプションがデフォルトになっている.
$ bats addition.bats ✓ addition using bc ✓ addition using dc 2 tests, 0 failures
テストがエラーになると,以下のような出力となる.
$ bats echo.bats ✗ echo (in test file echo.bats, line 5) `[ "${result}" -eq 1000 ]' failed 1 test, 1 failure
--tap
オプションを付けると,TAP (Test Anything Protocol) フォーマットで出力される.TAP は今まで聞いたことがなかった.
$ bats --tap addition.bats 1..2 ok 1 addition using bc ok 2 addition using dc
なお,複数の Bats を実行することもできる.
$ bats *.bats ✓ addition using bc ✓ addition using dc ✓ addition using bc ✓ addition using dc 4 tests, 0 failures
setup と teardown
多くのテストフレームワークで使える setup
と teardown
も用意されている(テスト群の最初と最後にフックする).以下のように関数を定義して使う.
#!/usr/bin/env bats setup() { touch bats.log } teardown() { rm bats.log } @test "echo with setup and teardown" { result="$(echo 100)" [ "${result}" -eq 100 ] }
関数をテストする
Bats の実行方法がわかったので,次は functions.sh
を用意して,引数に渡した文字列を大文字に変換する関数を実装した.
#!/bin/sh ####################################### # 大文字に変換する # Arguments: # $1 WORD ####################################### upper_case() { echo $1 | tr '[:lower:]' '[:upper:]' }
Bats は以下のようになる.関数をテストするので setup
で functions.sh
を読み込み,Bats の run
で関数を呼び出している.
#!/usr/bin/env bats setup() { . functions.sh } @test "upper case for ruby" { run upper_case ruby [ "${status}" -eq 0 ] [ "${output}" == "RUBY" ] }
run
の結果は Bats の組み込み変数に入るため,これらをテスト結果として使う.
${status}
... ステータスコード${output}
... 出力結果${lines}
... 出力結果(配列)
bats functions.bats
✓ upper case for ruby
1 test, 0 failures
Dockerized とは相性が悪そう
CircleCI 2.0 でテストを実行しようと思って,Bats を Dockerized したけど(Alpine と Amazon Linux),Bats を実行するコンテナにライブラリなどが必要になるため,例えば Bats のサンプルコードだと bc
も dc
も入ってなく,エラーになる.ecs-deploy では,必要なライブラリを Dockerfile でインストールしている.
✗ addition using bc (in test file app/addition.bats, line 4) `result="$(echo 2+2 | bc)"' failed with status 127 /tmp/bats.36.src: line 4: bc: command not found ✗ addition using dc (in test file app/addition.bats, line 9) `result="$(echo 2 2+p | dc)"' failed with status 127 /tmp/bats.36.src: line 9: dc: command not found 2 tests, 2 failures
試しに Dockerized Bats を使って CircleCI 2.0 でテストできるようにしてみた.ただしこれは,ライブラリに依存しない状態で動いているので,参考程度という感じ.
まとめ
- シェルスクリプトのテストフレームワーク Bats を試してみた
- 運用系でシェルスクリプトを使う場面はまだまだあると思うので,テストコードが書けるとメンテナンスしやすくなる
- シェルスクリプトの関数ごとにテストを書けるので,そこそこ柔軟にテストコードが書けそう