rcmdnk's blog

BATS~蝙蝠地獄~ コレクターズ・エディション [DVD]

(Bashの)シェルスクリプトに関してテストを導入するために フレームワークとしてBatsを導入します。

bats

シェルスクリプトのテストツールとして恐らく一番有名なツール。

オリジナルはこちら。

こちらは4年くらい前に更新が止まっていますが、 個人でメンテナンスを続けていくことが難しくなったときに みんなで続けていこうとして使われる様になったのが 以下のレポジトリ。

batsというアカウントはすでに他に取られていたのでこういう名前になった模様。

Call for Maintainers · Issue #150 · sstephenson/bats

Information about community-maintained fork · Issue #236 · sstephenson/bats

なので基本的にはbats-coreを使ったほうが新しい機能が入っていたりして良いです。

どちらもインストールするコマンドはbatsです。

ただ、batsyumaptで入れられますが、これらはオリジナルの方のもので、 ba-ts-coreに関してはまだ用意されていません。

Create bats-core packages to install easilly on linux · Issue #103 · bats-core/bats-core

bats-coreの方で特に新しい機能としてはbatsファイル探すときに-rによるリカーシブな検索ができるかどうか、というのが一番大きいところです。

Releases · bats-core/bats-core

それが必要なければ取り敢えずは古いbatsでも使える事は使えます。

Linuxでyumやaptで入れたい場合には古いので我慢するのもあり。

一方、Homebrewにはbats-coreもあります。

$ brew install bats-core

で入れられます。batsのFormulaも残っているので、これと同時に入れてしまうとファイルが衝突してしまうので 気をつけてください。通常bats-coreの方だけ入れておけばOKです。

LinuxでもHomebrewを使ってbats-coreを入れる事もできます。

batsの使い方

スクリプト言語の様にShebangにbatsを指定してスクリプトを書いていくか、 書いたスクリプトをbatsコマンドの引数に渡すことで実行します。

test.bats
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/env bats

setup() {
  test_file="./test.txt"
  touch "$test_file"
}

teardown() {
  rm -f "$test_file"
}

@test "addition using bc" {
  result="$(echo 2+2 | bc)"
  [ "$result" -eq 4 ]
}

@test "addition using bc (fail)" {
  result="$(echo 2+1 | bc)"
  [ "$result" -eq 4 ]
}

@test "check file" {
  [ -f "$test_file" ]
}

@test "skip test" {
  skip
  [ ! -f "$test_file" ]
}

@test "normal command" {
  ls
}

こんな感じのファイル。

各テストユニットは@test "<description>" { <test> } といった感じの書式で定義します。

テスト内容はシェルスクリプトで書いていけばOK。

上の例だと最後にテスト演算子([, ])で最後のチェックを行っているのが多いですが、 最後のテストのように通常のコマンドだけでもテストは出来ます。

途中でエラーステータスを返す行があればそこで終了です。

また、成功した場合にはコマンドの出力は表示されません、

失敗した場合、その失敗したコマンドが出力を出していればそれも表示します。

また、@testユニットの中にskipコマンドを入れるとそのテストはスキップされます。

各テストは独立に環境が作られますが、 setup()関数を定義しておくとここで共通の設定が定義できます。

またteardown()関数ですべてのテストが終わった後の処理を定義することも出来ます。

とりあえず上のファイルを実行して見ると、

$ chmod 755 ./test.bats
$ ./test.bats
 ✓ addition using bc
 ✗ addition using bc (fail)
   (in test file a.bats, line 19)
     `[ "$result" -eq 4 ]' failed
 ✓ check file
 - skip test (skipped)
 ✓ normal command

5 tests, 1 failure, 1 skipped

と言った具合に結果が出ます。

こんな感じでbats自体がbashで書かれているため bash用のテストツールという感じが強いですが、 使い方としてはコマンドラインで実行できることがらであれば そのまま簡単にテストにすることが出来ます。

assertion

batsの機能だと、各テストの結果として成功か失敗か、しか分からず どの様な失敗だったのかちょっと分かりづらいところがあります。

これを解決するためにbats用のassertionツールが色々作られていますが、 以下のものが多分一番使われているもの。

使えるのは以下の関数:

  • assert: 引数に置く評価が成功する
  • refute: 引数に置く評価が失敗する
  • assert_equal: 第一引数が第二引数に一致
  • assert_success: 直前のコマンドが成功する(終了ステータス0)
  • assert_failure: 直前のコマンドが失敗する(終了ステータス0以外)。引数を与えた場合にはその終了ステータスでの終了。
  • assert_output: 直前コマンドの出力と引数が一致する
  • refute_output: 直前コマンドの出力と引数が一致しない
  • assert_line: 直前コマンドの出力の中に引数と一致する行がある
  • refute_line: 直前コマンドの出力の中に引数と一致する行がない

下4つにある出力との比較には正規表現も使えます。

bats-assertを使うにはまず bats-assertbats-support の2つを用意する必要があります。

適当なディレクトリで、

$ git clone https://github.com/ztombol/bats-assert
$ git clone https://github.com/ztombol/bats-support

しておきます。

これらに対してsetup()の中で

setup() {
  load ./bats-assert/load
  load ./bats-support/load
  ...
}

の様にloadを使ってレポジトリ内のloadファイルを呼ぶことで 必要な関数を読み込むことができます。

これらを使って上のテストスクリプトを書き換えると

test_assert.bats
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/usr/bin/env bats

setup() {
  load ./bats-assert/load
  load ./bats-support/load

  test_file="./test.txt"
  touch "$test_file"
}

teardown() {
  rm -f "$test_file"
}

@test "addition using bc" {
  result="$(echo 2+2 | bc)"
  assert_equal "$result" 4
}

@test "addition using bc (fail)" {
  result="$(echo 2+1 | bc)"
  assert_equal "$result" 4
}

@test "check file" {
  assert [ -f "$test_file" ]
}

@test "skip test" {
  skip
  refute [ -f "$test_file" ]
}

@test "normal command" {
  ls
  assert_success
}

こんな感じになります。

これを実行すると

$ chmod 755 ./test_assert.bats
$ ./test_assert.bats
 ✓ addition using bc
 ✗ addition using bc (fail)
   (from function `assert_equal' in file ./bats-assert/src/assert.bash, line 91,
    in test file test.bats, line 22)
     `assert_equal "$result" 4' failed

   -- values do not equal --
   expected : 4
   actual   : 3
   --

 ✓ check file
 - skip test (skipped)
 ✓ normal command

5 tests, 1 failure, 1 skipped

といった出力になります。 失敗したときに4であるべきところが3であった、という事がわかります。

先程は評価式そのものが表示されるだけだったので どういう値になってしまって失敗したか分かりませんでしたが、 これなら3になってしまった事が分かるので対処しやすくなります。

シェルスクリプトでなくても使える

Bats自体がBashのシェルスクリプトで作られてることがあり Bash用のテストフレームワークと言う面がありますが、 実際には上記の様にコマンドの結果をチェックすることを行う、という形なので Zshでも他の言語で作られたコマンドラインツールでも 実行結果をチェックすることには使えます。

Sponsored Links
Sponsored Links

« macOS 10.15 Catalinaへアップグレード GitHub Actionsを使ってsentakuのシェルスクリプトに対するテストの実装 »

}