併せて読みたい: ShellScript - そのシェルスクリプトのあるディレクトリに移動する - Qiita [キータ]
とあるプロジェクトが,
APP_ROOT
|- a.sh
`- test/
|- run.sh
|- a.txt
|- a-expected.txt
`- shunit2
という構成になっているとします.a.sh を実行すると test/a.txt の内容が変わって test/a-expected.txt と一致することをテストしたいとします.このとき test/run.sh は以下のようになりました.
# ! /bin/sh
TEST_DIR=`dirname $0`
setUp()
{
PREV_DIR=$PWD
cd $TEST_DIR
cp a.txt a.txt.bk
}
tearDown()
{
if [ -f a.txt.bk ]; then
mv a.txt.bk a.txt
fi
cd $PREV_DIR
}
testA()
{
../a.sh
diff a.txt a-expected.txt
assertEquals 0 $?
}
# load shunit2
. $TEST_DIR/shunit2
サンプルなんかでは最後の行は . ./shunit2 と書かれているんですが,test/run.sh をどこから実行してもいいようにしたかった (思えばこれがそもそもどうでもいいかもしれませんが…) ので,まずそれを . $TEST_DIR/shunit2 とします.TEST_DIR の取得方法は先述のエントリの通りですね.
ここからがアレでした.
そもそも cd $TEST_DIR して . ./shunit2 にすればええやん?と思ってたのですが,なんと shUnit2 さんは SHUNIT_PARENT なる変数を用いて shunit2 のあるディレクトリを監視し,そこから grep でテストスクリプト (今回なら run.sh) の中身を見てよしなにしてくれる仕様になってます.
そうすると何が起こるかって,今自分で cd $TEST_DIR して test の中にいるのに,そこから test/run.sh というパスになるファイルを扱おうとしてくれるわけです.はい,当然見つからないですね../run.sh なら良かったんですが.
※うちの shunit2 は自分で make build して作ったものですからもしかしたら微妙な差異はあるのかもです.
※うちの環境での話をするなら,shunit2 内での件の grep は 934 行目で,SHUNIT_PARENT の設定は 36 行目からの処理で行われていました.
ということは,cd $TEST_DIR するのはテストの実行時だけにしなければなりません.
なので上記のように setUp 内で cd $TEST_DIR を行う必要があるわけです.
で,次に cd $TEST_DIR しっぱなしでいるとテストが追加されたときにまずいことになります.最初の 1 つのテストはいいんですが,次のテストで再び cd $TEST_DIR しようとしても今既にそこに居るので「そんなファイル or ディレクトリ無いです」って言われます.エラーにこそなりませんが出力が汚くなります.警告の表示を無視するとかプログラマとしてやりたくないですよね.なので一々 setUp 時点での $PWD を記録しておいて,tearDown 内で戻るわけです.
ん?じゃあ oneTimeSetUp 使ってそこで cd $TEST_DIR すればいいじゃんって?
ダメなんです… 先述の grep の処理はなんと oneTimeSetUp の「後」に行われるんです… なんてこった.
そういうわけで,こういう形に落ち着いたわけです.
うーん,テストの書き方が難しいというのはテストという目的としてどうなのか… 検算のやり方が本来の答えを導き出す手法未満の難易度じゃないとテストって意味が無い気がするんですよね…