#author("2020-02-12T01:24:51+09:00","default:haikikyou","haikikyou")
#author("2020-02-12T02:55:02+09:00","default:haikikyou","haikikyou")
[[moritetuのIT関連技術メモ]]

#contents

* baut [#v1037d10]

Bashで書かれたテストツール。~
batsのようにコマンドラインベースでプログラムの振る舞いをテストすることを目的としている。~
テストプログラム自体もすべてBashであり、ツール特有のシンタックスはない。
テストプログラム自体もすべてBashであり、ツール特有のシンタックスはない。~
XUnitのような感覚で使える。

* [#mbc044f0]

* インストール [#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]

** run [#y9f374d2]

後に続くコマンドを実行し、結果を変数に格納する。

|~変数|~説明|h
|result|stdoutとstderrの結果|
|status|コマンドの終了ステータス|
|lines|stdoutとstderrの結果の行単位の配列|

** 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]

run2と同じ、リダイレクトやパイプなどを含むコマンドを実行する。

** 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]

テストプロセスを停止する。

** skip [#t06affb7]

テストをスキップする。

** 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/


トップ   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
目次
ダブルクリックで閉じるTOP | 閉じる
GO TO TOP