LoginSignup
0
0

More than 5 years have passed since last update.

bats ファイルのグローバルスコープには正常終了するコマンドだけを書く

Last updated at Posted at 2017-12-20

はじめに

  • Bash のテストフレームワーク bats に関する記事
  • bats ファイルのグローバルスコープ 1 に書いたコマンドが異常終了 ($? -ne 0) すると、bats も異常終了する話

bats とは?

Bash スクリプトのテストツールです。参考サイトを以下に挙げます。

起きた問題

bats コード

以下を行うだけのコードです。わかりやすくするために実際のテストコードは端折っています。

  • env.sh を読み込む
  • /tmp/buffer.txt を初期化する
test.bats
#!/usr/bin/env bats

source ./env.sh

function setup() {
  : > /tmp/buffer.txt
}

実行結果

想定していた処理結果は以下です。

想定
$ ./test.bats 

0 tests, 0 failures
$ echo $?
0

しかし、実際は以下のように処理に失敗してしまい、テストも行われませんでした。

想定外
$ ./test.bats
$ echo $?
1

原因

source ./env.sh が原因でした。
具体的には、以下のように env.sh 内で開発環境か否かのチェックを行っていました。

env.shでダメだった箇所
hostname | grep 'dev'
if [ $? -eq 0 ]; then
  # 開発環境向けの処理
else
  # 本番環境向けの処理
fi

問題が発生するのは hostname | grep 'dev' の実行結果が 1 となるとき、すなわち開発環境でないときです。
ここで bats は、グローバルスコープに記述したコマンドが正常終了しなかった場合に、 bats 自体も異常終了して落ちてしまうようです。

解決策

2つ考えられます。

ラップする方法

異常終了するコマンドを if でくくり、異常終了をラップします。

ダメだったやり方
hostname | grep 'dev'
if [ $? -eq 0 ]; then
  # 開発環境向けの処理
  :
良さげなやり方
if hostname | grep 'dev'; then
  # 開発環境向けの処理
  :

後者の方がスマートでいいですね。

無理やりな方法

正常終了しないコマンドは || : で無理やり正常終了させたことにします。

test.bats
source ./env.sh || :

source が失敗した場合は、 : つまり「何もしない」コマンドが実行されて必ず正常終了を返します。
これによって、 source がどちらに転んでも正常終了を返す仕組みを作ります。
ただ、エラーハンドリングという観点でみると杜撰なので、前者の if を使った方法を好ましく思います。

まとめ

  • bats を使うときはコマンドの戻り値 $? を意識する
  • 異常終了しそうなコマンドは if でラップするか、無理やり正常終了化させることで bats の強制終了を回避する

所感

  • bats の思想に触れてみると、「スクリプト内のすべてのコマンドは 0 で終了すること」がシェルスクリプトの1つの理想形なのかな、と感じたりした

  1. 本記事では「setupteardown@test などのファンクション外」のことを指しています。もっとも、シェルスクリプトにおいてはどこでもグローバルと呼べそうな気もしますが… 

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0