Bash のシェルスクリプトは、エンジニアが片手間に書いて使う DIY 的な使い捨てスクリプトになりがちぎみだけれども。
Bash のシェルスクリプトを作ってオープンソースとして公開している手前、
「きちっとテストを入れたいなぁ」と思っていろいろ Bash のテストどうやるの? というところから始まって
どんなアプローチがあるのだろうといろいろ調べたり試したり。
結果、Bashテストフレームワークとして「Bats」がシンプルすぎるぐらいに良かったので採用してみました。
Bashテストフレームワーク「Bats」とは
Bats の正式名称は、Bash Automated Testing System。
ドキュメントには、
Bats is a TAP-compliant testing framework for Bash.
(訳: BatsはBash用のTAP準拠のテストフレームワークです。)
とある。
使い方は、.bats
拡張子を付けたファイルにテストケースを書いていくだけ。
例えば、example.bats に以下を書いて
#!/usr/bin/env bats
@test "status - return 0 exit code" {
run bash -c 'exit 0'
[ "$status" -eq 0 ]
}
@test "output" {
run bash -c 'echo -e "abc"'
[ "$output" = "abc" ]
}
@test "lines" {
run bash -c 'echo -e "abc\ndef\nghi"'
[ "${lines[0]}" = "abc" ]
[ "${lines[1]}" = "def" ]
[ "${lines[2]}" = "ghi" ]
}
テストを走らせると、
bats --tap example.bats
テスト結果が得られます。
1..3
ok 1 status - return 0 exit code
ok 2 output
ok 3 lines
テストケースのプロセスは、run
でコマンドを実行し、
その結果が 3つの変数に保存されます。
$status
-exit status
を保存$output
- 標準出力またはエラー出力を保存$lines
- 標準出力またはエラー出力を行単位で配列で保存
それら変数を確かめたり、アサーションしたりする。
setup
, teardown
もあるので、
いろんな設定を想定したテストケースが作れると思います。
Bash だけでなくいろんな言語のコマンドラインツールで使えて
シンプルなテストには、もってこいのテストフレームワークです。
ヘルパースクリプト「Bats Assertion」
今回、その Bats のヘルパースクリプト「Bats Assertion」をつくりました。
Assertion 系のヘルパースクリプトは、ほかにもありましたが、
テストを書くこと自体がテストドキュメントになる。
もっとシンプルに書けて、テストを書くことが億劫にならず、
テストを育てていく感じにならないかなぁと思って設計してみました。
使い方は、ヘルパースクリプト「Bats Assertion」をダウンロードして
テストファイル内で Bats の load
コマンドで読み込むだけ。
load bats-assertion/bats-assertion
読み込むと、以下の assertion 系のコマンドが使えるようになります。
- assert_success
- assert_failure
- assert_status
- assert_equal
- assert_fail_equal
- assert_match
- assert_fail_match
- assert_lines_equal
- assert_fail_lines_equal
- assert_lines_match
- assert_fail_lines_match
それぞれのコマンドの詳細は Assertion Reference を参照してみてください。
ヘルパースクリプト「Bats Assertion」で書き換えると
先の example.bats をヘルパースクリプト「Bats Assertion」で書き換えると、
こんな感じになります。
#!/usr/bin/env bats
load bats-assertion/bats-assertion
@test "status - return 0 exit code" {
run bash -c 'exit 0'
assert_success
}
@test "output" {
run bash -c 'echo -e "abc"'
assert_equal "abc"
}
@test "lines" {
run bash -c 'echo -e "abc\ndef\nghi"'
assert_lines_equal "abc" 0
assert_lines_equal "def" 1
assert_lines_equal "ghi" 2
}
assertion 系のコマンドを体系化することでテストが書きやすく、
一目見ただけで分かりやすいテストケースになって
そのままテストドキュメントにもなればなぁと思います。