やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

BashテストツールBatsをインストールし使ってみた

独特のクセがある。パス絡みで使いづらい。

Bats

github.com

ダウンロード&インストール

$ git clone https://github.com/sstephenson/bats.git
$ cd bats
$ sudo ./install.sh /usr/local
Installed Bats to /usr/local/bin/bats

使ってみる

テストコードを書いてみる。

A.bats

#!/usr/local/bin/bats

@test "test Hello" {
    [ "Hello" = `echo 'Hello'` ]
}

実行する。

$ bats A.bats 
 ✓ test Hello

1 test, 0 failures

失敗させてみる

B.bats

#!/usr/local/bin/bats

@test "test Hello" {
    [ "Hello" = `echo 'xxxxx'` ]
}
$ bats B.bats 
 ✗ test Hello
   (in test file B.bats, line 4)
     `[ "Hello" = `echo 'xxxxx'` ]' failed

1 test, 1 failure

テスト名のほか、ファイル名、行数、テストコードが出力された。失敗した箇所が特定できる。

テスト対象が外部ファイルのとき

ふつうはそうだろう。loadコマンドを使う。

  • ./
    • src/
    • test/
      • A.bats

A.bash

EchoHello () { echo 'Hello'; }

A.bats

@test "test Hello" {
    load ../src/A
    [ "Hello" = `EchoHello` ]
}

ここで罠がある。以下の条件でないとloadは使えない。外部ファイルを参照するためには必須条件。

  • load対象ファイルの拡張子は.bashのみ
  • loadするときは拡張子を省略せねばならない

これが非常に不満。今まで.shで書いてきたのに、それらはBatsで読み込めずテストできない。

load

ファイルを探せない

原因:loadするとき、ファイル名の末尾に拡張子.bashが勝手に付け加えられるから 解決:load対象の拡張子は必ず.bash。かつloadするときは拡張子を必ずとる

.shだと読めずテストできない残念仕様。

A.bats

load A.sh
$ bats A.bats
bats: /.../A.sh.bash does not exist

A.shを対象にしたいのに、「A.sh.bashが無い」と怒る。そんなファイルを指定した覚えはないのに。

さては.bash以外認めないのか? と思い、A.shA.bashにリネームするも失敗。

A.bats

load A.bash
$ bats A.bats
bats: /tmp/work/Bats.Test.20180403090444/src/C.bash.bash does not exist

.bash.bashってなんだよ。どうやらbatsが勝手に付け加えてしまうようだ。

呼出時に拡張子をとることで成功。

A.bats

load A
$ bats A.bats
 ✓ test Hello

1 test, 0 failures

つまり、以下の条件を満たさねばloadは失敗し、テスト失敗となる。

  • テスト対象ファイルの拡張子はbashであること
    • shだとファイルが見つからない)
  • loadするときは拡張子を抜いたファイル名を指定すること
    • (batsが勝手に.bashを末尾に追加するので)

これ、使いづらい。省略時は自動補完して探すならまだしも、.bash限定かつ呼出時は省略せねば参照不可って……。あと.shも探してやってください。

sourceは使えない

loadなんて使わず、.sourceコマンドで解決してやろうと企むも失敗。

A.bats

path_dir_this=$(cd $(dirname $0); pwd)
. "${path_dir_this}/A.sh"
$ bats A.sh
/usr/local/libexec/A.sh: そのようなファイルやディレクトリはありません

確認してみると、A.batsの起動引数は以下のようになるらしい。

引数
$0 /usr/local/libexec/bats-exec-test
$1 (空)

テスト対象ファイルの絶対パスが欲しいのに……。救いはない。

run

runコマンドでコマンドのテストができる。$status$outputで終了コードと出力結果を参照できる。

が、環境変数PATHが通っていないとテストエラーになる。

しかもメッセージからはエラーの原因がわからない。

test Hello
   (in test file /.../A.bats, line ...)
     `[ "Hello" = "$output" ]' failed

そこで、echo $outputしてみる。

@test "test Hello" {
    run A
    echo $output
    [ "Hello" = "$output" ]
    [ 0 -eq $status ]

以下のメッセージが表示される。

test Hello
   (in test file /.../A.bats, line ...)
     `[ "Hello" = "$output" ]' failed
   /usr/local/libexec/bats-exec-test: 行 58: A: コマンドが見つかりません

run AのようにAと指定したが、「コマンドが見つかりません」と怒られる。

フルパス指定すれば実行できた。が、普通は相対パスで指定したいもの。

load, run, どちらのコマンドもパス絡みで不都合がある。

構文エラー時にメッセージが表示されなかった

構文エラー: 予期しないファイル終了 (EOF) です

A.sh

EchoHello () { echo 'Hello'; }

上記のようにすべきところ、;を忘れてしまって以下のようにした。

EchoHello () { echo 'Hello' }

これをbashで実行すると以下のエラーになる。

$ bash A.sh
A.sh: 行 2: 構文エラー: 予期しないファイル終了 (EOF) です

Batsでは以下の表示になった。

$ bats A.bats
 ✗ test Hello

1 test, 1 failure

ファイル名、行数がない。エラーの原因不明。なにもわからない。

追記

 リポジトリが管理されていない。新しいリポジトリから入手すべし。