- 追加された行はこの色です。
- 削除された行はこの色です。
#author("2020-02-12T02:55:02+09:00","default:haikikyou","haikikyou")
#author("2020-02-14T21:06:11+09:00","default:haikikyou","haikikyou")
[[moritetuのIT関連技術メモ]]
#contents
* baut [#v1037d10]
Bashで書かれたテストツール。~
batsのようにコマンドラインベースでプログラムの振る舞いをテストすることを目的としている。~
テストプログラム自体もすべてBashであり、ツール特有のシンタックスはない。~
XUnitのような感覚で使える。
* インストール [#c72c7dc1]
任意の場所にソース一式をダウンロードして、&code(){bin};ディレクトリにパスを通すだけである。~
&code(){install.sh};を実行すれば同じことをしてくれる。
#geshi(bash){{{
$ git clone https://github.com/moritetu/baut.git
$ cd baut
$ source install.sh
$ baut run test
}}}
パスが通っていれば、&code(){-h};でUsageを確認できる。
#geshi(bash){{{
$ baut -h
Usage: baut [-v] [-h] [--d[0-4]] [run|<command>] [<args>]
OPTIONS
-v, --version Show version.
-h, --help Show usage.
--d[0-4] Set log level to TRACE(0), DEBUG(1), INFO(2), WARN(3), ERROR(4)
COMMANDS
compile Compile a test script file.
init Generates test files from a template.
report Format the result of 'baut test' execution.
run Run tests.
test Run tests in a file and print its result.
Ordinally this command is called in 'run' command.
Show more available information about a specific command.
'baut <command> [-h|--help]'
}}}
* テスト [#m553508e]
** テストプログラム [#e5df3fd3]
- テストファイルは、拡張子が&code(){*.sh};である。
- テストファイル名は、&code(){test_};で始まる必要がある。
- テスト単位は、シェルの関数であり、&code(){test_};で始まる関数はテスト対象である。~
&code(){test_};で始まる関数名でなくともアノテーション&code(){@Test};が付与されている関数はテスト対象となる。
- &code(){#:};は特別な意味を持ち、&code(){#:}; の後には&code(){@アノテーション};などを記述する。
- ファイル内のテストは上から順に実行される。
#geshi(bash){{{
#!/usr/bin/env bash
#: @BeforeAll
function setup_all() {
: 本ファイルのすべてのテスト実行前に一度呼ばれる
: # 本ファイルのすべてのテスト実行前に一度呼ばれる
}
#: @BeforeEach
function setup() {
: 各テスト前に一度呼ばれる
: # 各テスト前に一度呼ばれる
}
#: @Test(テストの内容について記述できる)
test_ng_sample() {
fail "Not implemented"
}
#: @Test
test_ng_sample2() {
run echo "bar"
[ $status -ne 0 ] || fail "exit status should not be 0, but '$status'" "result: $result"
}
#: @Test
test_ok_sample() {
run echo "hello baut"
[ "$result" = "hello baut" ]
[ $status -eq 0 ]
}
#: @Test
test_skip_sample() {
run echo "hello baut"
skip "Good bye!"
echo "Not reach here"
}
#: @Test
test_wait_until() {
local pidfile="$(__DIR__)/sample.pid"
eval "sleep 2 && echo $BASHPID > $pidfile" &
wait_until --retry-max 3 "[ -e '$pidfile' ]"
rm $pidfile ||:
}
#: @AfterEach
function teardown() {
: 各テストの実行後に呼ばれる
: # 各テストの実行後に呼ばれる
}
#: @AfterAll
function after_all() {
: 本ファイルのすべてのテスト実行後に呼ばれる
: # 本ファイルのすべてのテスト実行後に呼ばれる
}
}}}
実行すると以下のようになる。
#geshi(bash){{{
$ baut r test_sample.sh
1 file, 5 tests
#1 /tmp/test_sample.sh
x テストの内容について記述できる
Not implemented
# Error(1) detected at the following:
# 13 #: @Test(テストの内容について記述できる)
# 14 test_ng_sample() {
#=> 15 fail "Not implemented"
# 16 }
# 17
x test_ng_sample2
exit status should not be 0, but '0'
result: bar
# Error(1) detected at the following:
# 19 test_ng_sample2() {
# 20 run echo "bar"
#=> 21 [ $status -ne 0 ] || fail "exit status should not be 0, but '$status'" "result: $result"
# 22 }
# 23
o test_ok_sample
~ test_skip_sample # SKIP Good bye!
o test_wait_until
#$ 5 tests, 2 ok, 2 failed, 1 skipped
💥 1 file, 5 tests, 2 ok, 2 failed, 1 skipped
Time: 0 hour, 0 minute, 3 seconds
}}}
** テストスイートの実行 [#s403cc39]
ディレクトリを指定して実行すれば、ディレクトリ下のテストを順に実行する。~
テストファイルの実行順序は決まっていない。
#geshi(bash){{{
$ baut run testdir
}}}
2階層以上にもテストファイルが存在する場合は、&code(){-r};をつける。
#geshi(bash){{{
$ baut run -r testdir
}}}
* コマンド [#g817c193]
* 特徴・機能 [#cda5c009]
** run [#y9f374d2]
** コマンド [#g817c193]
*** run [#y9f374d2]
後に続くコマンドを実行し、結果を変数に格納する。
|~変数|~説明|h
|result|stdoutとstderrの結果|
|status|コマンドの終了ステータス|
|lines|stdoutとstderrの結果の行単位の配列|
** run2 [#u2556e0b]
*** run2 [#u2556e0b]
後に続くコマンドを実行し、結果を変数に格納する。~
runと違うのは、stdoutとstderrを別々に扱うこと。
|~変数|~説明|h
|result|stdoutの結果|
|status|コマンドの終了ステータス|
|lines|stdoutの結果の行単位の配列、stdout_linesと同じ|
|stdout|stdoutの結果|
|stderr|stderrの結果|
|stdout_lines|stdoutの結果の行単位の配列|
|stderr_lines|stderrの結果の行単位の配列|
#geshi(bash){{{
myfunc() {
echo "hoge"
echo "bar" >&2
exit 1
}
test_run() {
run echo "hoge"
[ "$result" = "hoge" ]
[ "${lines[0]}" = "hoge" ]
(( status == 0 ))
}
test_run2() {
run2 myfunc
[ "$result" = "hoge" ]
[ "${stdout_lines[0]:-}" = "hoge" ]
[ "${stderr_lines[0]}" = "bar" ]
[ "$stdout" = "hoge" ]
[ "$stderr" = "bar" ]
(( status == 1 ))
}
}}}
** eval2 [#b6d06a17]
*** eval2 [#b6d06a17]
run2と同じ、リダイレクトやパイプなどを含むコマンドを実行する。
** wait_until [#w50e20d3]
*** wait_until [#w50e20d3]
実行に時間のかかるコマンドを待ち合わせる。
#geshi(bash){{{
test_wait_until() {
local pidfile="$(__DIR__)/sample.pid"
eval "sleep 2 && echo $BASHPID > $pidfile" &
wait_until --retry-max 3 "[ -e '$pidfile' ]"
test -e "$pidfile" && rm "$pidfile" ||:
}
}}}
** stop [#jb69ffb7]
*** stop [#jb69ffb7]
テストプロセスを停止する。
** skip [#t06affb7]
*** skip [#t06affb7]
テストをスキップする。
** fail [#we9d1b38]
*** fail [#we9d1b38]
テストを失敗させる。
#geshi(bash){{{
test_skip() {
skip "This test is skipped"
echo "not reach here"
}
test_fail() {
fail "Not implementation"
}
test_stop() {
stop "halt test"
}
}}}
* 参考リンク [#g7790abf]
- https://github.com/moritetu/baut
- https://baut.readthedocs.io/en/latest/