CLOVER🍀

That was when it all began.

Batsのbats_load_library関数で、ロードするライブラリーのパスを簡潔に指定する

これは、なにをしたくて書いたもの?

前にBashのテスティングフレームワークである、Batsのチュートリアルを試しました。

Bashのテスティングフレームワーク、Batsを試す - CLOVER🍀

この時、bats-assertおよびbats-supportをロードするのにload関数で絶対パスを指定するのが嫌だなと思っていたのですが、bats_load_libraryを
使うと少し改善されそうなので試してみることにしました。

bats_load_library関数

bats_load_libraryは、システムにインストールされたライブラリーをロードする関数です。

Writing tests / bats_load_library: Load system wide libraries

BATS_LIB_PATHという環境変数を使って、次の動作を行うようです。

  • ライブラリーのファイルをBATS_LIB_PATHからの相対パスとして解釈する
  • ライブラリー名には、load.bashというエントリーポイントを示すファイルがある

たとえば、BATS_LIB_PATH~/.bats/libs:/usr/lib/bats:区切りで複数パスの設定可)と設定されている場合に以下のように書くと

setup() {
  bats_load_library test_helper
}

test_helperの探索パスは以下になります。

  • ~/.bats/libs/test_helper
  • ~/.bats/libs/test_helper/load.bash
  • /usr/lib/bats/test_helper
  • /usr/lib/bats/test_helper/load.bash

ライブラリーの一部だけをロードしたい場合や、エントリーポイントがload.bashではない場合はbats_load_library関数の引数に指定する必要が
あります。

たとえば以下の例だと

setup() {
  bats_load_library library_name/file_to_load
}

探索パスは以下になります。

  • ~/.bats/libs/library_name/file_to_load
  • ~/.bats/libs/library_name/file_to_load/load.bash
  • /usr/lib/bats/library_name/file_to_load
  • /usr/lib/bats/library_name/file_to_load/load.bash

ちなみにディストリビューションのパッケージのメンテナー向けではありますが、BATS_LIB_PATH/usr/lib/bats/に設定することが推奨されて
いるようです。

では、少し試してみましょう。

環境

今回の環境はこちら。

$ bash --version
GNU bash, バージョン 5.2.21(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2022 Free Software Foundation, Inc.
ライセンス GPLv3+: GNU GPL バージョン 3 またはそれ以降 <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.


$ apt search ^bats.*
ソート中... 完了
全文検索... 完了
bats/noble,noble,now 1.10.0-1 all [インストール済み]
  bash automated testing system

bats-assert/noble,noble,now 2.1.0-3 all [インストール済み]
  Helper library providing common assertions for Bats

bats-file/noble,noble,now 0.4.0-1 all [インストール済み]
  Helper library providing filesystem-related assertions for Bats

bats-support/noble,noble,now 0.3.0-4 all [インストール済み、自動]
  Supporting library to test bats helper libraries

bats_load_library関数を使ってみる

以前のチュートリアルのエントリーで使ったコードを、bats_load_library関数で書き換えてみたいと思います。

Bashのテスティングフレームワーク、Batsを試す - CLOVER🍀

テスト対象。

src/project.sh

#!/bin/bash

echo 'Welcome to our project!'

echo 'NOT IMPLEMENTED!' >&2
exit 1

テストコード。

test/test.bats

setup() {
    load '/usr/lib/bats/bats-support/load'
    load '/usr/lib/bats/bats-assert/load'

    DIR=$(cd $(dirname $BATS_TEST_FILENAME) >/dev/null 2>&1 && pwd)
    PATH="$DIR/../src:$PATH"
}

@test "can run our script" {
    run project.sh
    assert_output --partial 'Welcome to our project!'
}

確認。

$ bats test/test.bats
test.bats
 ✓ can run our script

1 test, 0 failures

見てのとおり、bats-supportとbats-assertは/usr/lib/batsディレクトリー配下にあります。

setup() {
    load '/usr/lib/bats/bats-support/load'
    load '/usr/lib/bats/bats-assert/load'

    DIR=$(cd $(dirname $BATS_TEST_FILENAME) >/dev/null 2>&1 && pwd)
    PATH="$DIR/../src:$PATH"
}

では、bats_load_library関数を使ってテストコードをこのように書き換えてみます。

test/test.bats

setup() {
    # load '/usr/lib/bats/bats-support/load'
    # load '/usr/lib/bats/bats-assert/load'
    bats_load_library bats-support
    bats_load_library bats-assert

    DIR=$(cd $(dirname $BATS_TEST_FILENAME) >/dev/null 2>&1 && pwd)
    PATH="$DIR/../src:$PATH"
}

@test "can run our script" {
    run project.sh
    assert_output --partial 'Welcome to our project!'
}

確認。

$ bats test/test.bats
test.bats
 ✓ can run our script

1 test, 0 failures

テストをパスしました。いいですね。

BATS_LIB_PATHのデフォルト値?

ところで、今回はBATS_LIB_PATH環境変数を設定しているわけではありません。

$ env | grep BATS

今回はいったいどのような設定で動作したんでしょうね?

答えは、batsコマンドのようです。

https://github.com/bats-core/bats-core/blob/v1.10.0/libexec/bats-core/bats#L123

batsコマンドは、最後にlibexecディレクトリー内にあるコマンドを実行するようになっています。

$ tail -n 1 $(which bats)
exec env BATS_ROOT="$BATS_ROOT" "$BATS_ROOT/libexec/bats-core/bats" "$@"

この中に、BATS_LIB_PATH環境変数が定義されていない場合はデフォルト値が/usr/lib/batsになるようになっています。

$ grep BATS_LIB_PATH /usr/libexec/bats-core/bats
export BATS_LIB_PATH=${BATS_LIB_PATH-/usr/lib/bats}

せっかくなので確認してみましょう。

テストを書いて

test/lib.bats

setup() {
    bats_load_library bats-support
    bats_load_library bats-assert
}

@test "BATS_LIB_PATH default value" {
    assert_equal "$BATS_LIB_PATH" '/usr/lib/bats'
}

確認。

$ bats test/lib.bats
lib.bats
 ✓ BATS_LIB_PATH default value

1 test, 0 failures

OKですね。

おわりに

Batsのbats_load_library関数で、ロードするライブラリーのパスを簡潔に指定できることを確認してみました。

チュートリアルを扱った時はload関数しか知らなかったので「絶対パスを書くのは嫌だな…」と思っていたのですが、bats_load_library関数の
おかげでちょっと印象が変わりましたね。

せっかくなので使っていきましょう。