Baut

この記事は約12分で読めます。

はじめに(Summary)

Baut(Bash Unit test Tool)は、Bashで書かれたユニットテストツールです。シェルスクリプトだけでなくUnix/Linuxプログラムが期待通りの動作をするかを検証するのに有用です。

Bautが実行するテストプログラムは、単なるBashスクリプトです。特別なエディターやエディターモードも必要ありません。使い慣れたいつもの環境で簡単にテストを記述することができます。

Bautのテストプログラムは、以下のようになります。他のテストフレームワークと類似しています。

#:で始まる行は、続く記号に何らかの意味を持つ記述が来ることを示すメタコメント行です。メタコメント行には、@で始まる識別コードを記述します。@BeforeEach@AfterEachはそれぞれあるテスト開始前と終了時に呼ばれる関数です。1テストごとに呼ばれます。@Test(...)は、関数がテスト対象であることを示します。変わりに「test_*」にマッチする関数名であれば、@Testがなくてもテスト対象とみなします。functionキーワードはなくても問題ありません。@Ignoreが指定されたテストは無視されます。テスト対象に含まれないので、テストとしてカウントされません。

コマンドの実行が正しいか否かを確認するコードは通常のシェルの条件式です。set -eと同様にエラーを検出します。しかし、BautではERRトラップを使ってエラーを捕捉しているのでテスト自体はすぐに終了となりません。$resultは、runコマンドで実行したコマンドの標準出力及び標準エラー出力の結果が格納されています。

上記を実行した結果は以下のようになります。

分かりやすいように各関数の始めにechoで関数名を出力しました。上記では、テストファイルの11行目のrunコマンドでエラーになったことを示しています。テスト明細行には、1つのtestを実行し1つが失敗したことを示しています。最終の2行は、テスト全体をとしての明細です。Timeはテスト実行にかかった時間です。

インストール(Install)

インストールは特別な処理は必要ありません。githubからcloneするだけですぐに使用可能です。BautはBash4.2以上が必要です。

install.shは、git cloneしたbautの実行ディレクトリにパスを設定します。実行しなくても問題ありません。

ダウンロード後、以下のコマンドを実行するとhelpが表示されます。

使用方法(Usage)

runコマンド

テスト実行は、テストのためのシェルスクリプトを書きrunコマンドで実行するだけです。Bautは、指定されたテストファイルを読み、テスト実行のための準備を行なった後、テストファイルの各テストを実行していきます。

なお、テストファイルは以下の規約に従う必要があります。

  • test_*.shにマッチする。

テストの準備ができたらrunコマンドで実行します。

1つのテストファイル、1つのテストを実行し成功しました。

オプション

–stop-on-error

テストで失敗した場合、残りのテストを実行せずテストを終了します。

–dry-run

テストで実行される関数を表示します。テストは実行されません。

–no-color

出力カラーをoffにします。

–no-checksum

コンパイル時と実行時におけるチェックサムの比較検証をスキップします。

–format [oneline|default|tap|cat]

出力フォーマットを指定します。

  • onelineは、テスト名と結果を1行で出力します。テスト内での出力は破棄されます。
  • defaultは、デフォルト動作です。テスト内の出力もそのまま表示します。
  • tapは、tapプロトコルに沿った出力形式です。
  • catは、テスト実行時の加工のない出力です。主にデバッグ時にしか使用しません。

compileコマンド

通常、runコマンドから呼ばれるため明示的に呼ぶ機会はありません。Bautがテスト実行時に読み込むスクリプトを出力します。

testコマンド

通常、runコマンドから呼ばれるため明示的に呼ぶ機会はありません。compileされたファイルを引数にとりテストを実行します。

テストを書く(Writing Scripts)

テストファイルは、単なるBashスクリプトであることは先ほど説明の通りです。ここでは、テストの記述ルールについて説明します。

テストファイル(Test File)

テストファイル名は、test_で始まり、拡張子は.shである必要があります。拡張子が.shであるのは、通常のエディタにおいて特別な設定が不要なことを意味します。ファイルを開けば、シェルモードでインデントや補完などを使ってすぐにテストを記述することができます。

ファイル階層(Directory Structure)

テストファイルは、任意のディレクトリに設置可能です。ディレクトリの階層が深くても問題ありません。テストの種類別にディレクトリを分けてテストファイルを格納することができます。

runコマンドで-rオプションをつけることで、再帰的にテストファイルを探索します。

1番後のファイルはtest_options.shであり1つのテストを実行しテストが成功したことを示しています。続いて、2番目のテストファイルはtest_sample.shであり1つのテストを実行しテストが成功したことを示しています。

最後に、2つのファイルで合計2つのテストを実行し2つともテストにパスしたことを示しています。テスト実行には1secの時間がかかったとなっています。

テスト(Test)

関数(Function)

テストは、test_で始まる、または後述するAnnotationを使って指定します。テストは、テストファイルに書かれている順に実行されます。

functionキーワードはなくても問題ありません。以下は全てテスト対象となります。

アノテーション(Annotation)

テスト関数の先頭に付与することができます。テストに関する補足情報を@に続く識別子で指定します。

@BeforeAll

すべてのテストに先立って実行される処理に指定します。

@BeforeEach

各テストの最初に実行される処理に指定します。

@Test[(…)]

テストに指定します。(…)がある場合は、テスト結果に表示されるテスト名が...の部分で置換されます。

@Ignore

テストを無視します。

@Deprecated[(…)]

テストが非推奨であることを示します。テストの実行結果でDeprecatedという識別子が付加されます。

@TODO[(…)]

テストがTODOテストであることを示します。TAP用に用意されたものです。

@AfterEach

各テストの終了後に呼ばれます。テストに失敗しても実行されます。

@AfterAll

すべてのテストの最後に呼ばれます。

コマンドの実行

run <command>

外部コマンドやスクリプトの実行は、runコマンドを利用できます。runコマンドの実行結果(標準出力とエラー出力)は、$resultという変数に格納されます。また終了ステータスは、$statusという変数で参照可能です。また、出力の各行は$linesという変数で配列として参照できます。$linesには、出力が改行(\n)区切りで格納されています。

run2 <command>

こちらもrunと同様です。run2は、標準出力とエラー出力がそれぞれ別々の変数で参照できます。変数は、$stdout$stderrです。また各行は、$stdout_lines$stderr_linesで参照できます。

eval2 <command>

コマンドをevalで実行します。run2と同様に標準出力とエラー出力結果を別々の変数で参照することができます。

テストのスキップ

skip [<message>]

関数の処理内で以降の処理をスキップする場合に使用します。以下では、最終行のechoは実行されません。

実行すると以下のようになります。

テストの失敗

fail [<message>]

終了ステータスコード1でそのテストを終了します。

ファイルのロード

load <file> [<arg>…]

ファイルをsourceコマンドでインクルードします。一度読み込まれたファイルも再度ロード可能です。ファイルが存在しない場合は、エラー終了(exit)します。

load_if_exists <file> [<arg> …]

ファイルをsourceコマンドでインクルードします。一度読み込まれたファイルも再度ロード可能です。ファイルが存在しない場合は、終了ステータスコード以外を返します。exitしません。

require <file> [<arg> …]

ファイルをsourceコマンドでインクルードします。一度読み込まれたファイルは、重複ロードされません。ファイルが存在しない場合は、エラー終了(exit)します。

その他API

ヘルパー(Helpers)

追加機能のことを指します。

diff-helper

run_diffrun_diffxといったコマンドを追加します。runコマンドでは、通常、コマンドの実行結果を$result$lines$statusといった変数を用いて期待結果を比較しますが、このヘルパーではコマンドの実行結果をファイルに出力し、あらかじめ作成しておいた期待結果ファイルと比較を行ないます。

以下は、PostgreSQLにおけるリグレッションテストを模したテストになります。run_diffxは、コマンド実行結果で差分があれば、そこでテストがエラーとなります。run_diffは、テストはエラーとならず継続します。diffに失敗したか否かは$statusで確認できます。

ここでテストファイルが格納されるディレクトリとして、resultsexpectedというディレクトリが作成されます。expectedには、テスト関数名+.outという名前で期待結果ファイルを作成します。

差分が検出された場合は、テストエラーになります。続いて、resultsディレクトリ下に.diffファイルが作成されます。差分を確認して誤りを修正します。

内部構造(Baut Internal)

run〜レポート出力(From run to print report)

Bautはrunコマンドが実行されると、引数で指定されたテストファイルを読み込み、テストで実行される関数情報を収集します(compile)。この時、Annotationなどの情報を解釈します。続いて、読み込んだ内容からテスト実行ファイル(.bautファイル)を生成します。テスト実行ファイルは、Bautが一連のテストを実行するのに必要な構造で出力します。そして、このファイルもまた単なるBashスクリプトです。このテスト実行ファイルは、runコマンド実行時に一時ディレクトリに出力されテストの終了時に削除されます。

テスト実行における出力は、すべてレポートのためのスクリプトにパイプで送信されます。レポートスクリプトは、送信されてきた内容を解釈し、テストレポートを構築します。

実際にどのような形の実行ファイルが生成されているかを確認するには、compileコマンドを実行します。生成される結果は標準出力に書き出されます。以下出力例になります。

runコマンドでは、この生成された実行ファイルをsourceでインクルードし実行します。source "$BAUT_TEST_FILE"という行がありますが、この時点でテストファイルが読み込みされます。その後は、Bautがテストファイルに書かれた順番で逐次テストを実行していきます。

コンパイル及びテスト実行の単位は、ファイル単位です。テストファイルにおける環境変数やその他設定は、そのテストファイルのみで有効です。いずれのテストファイルでも共有で使用する設定がある場合は、共通設定ファイルとして切り出し、各種テストファイルの先頭でloadする必要があります。

レポートフォーマット(Report Format)

Bautでは、デフォルトでいつくかのレポートフォーマットを提供しています。独自でレポートフォーマットを作成したい場合は、以下のようにすることでカスタマイズ可能です。

  • ファイル名「local--test-report」を以下のディレクトリのいずれかに設置します。探索は、1から優先的に行われます。
    1. コマンドを実行したディレクトリ
    2. テスト実行ディレクトリ/helpers
    3. baut/libexec
    4. baut/helpers

例えば、出力行の先頭に時間を挿入したい場合は以下のようにします。

レポートスクリプトは、baut-exec-testからの出力を標準入力として受け取りますので、上記ではループで1行ずつ取り出し出力しています。このままでは、レポートのメタ行と出力が混合された形となるので、レポートスクリプトでは、特別な意味を持つ行を解釈して処理する必要があります。

特別な意味を持つ行とは、通常以下のようなフォーマットとなります。

例えば、テストの最初には以下のようなメッセージがレポートスクリプトに渡されます。

これは、READYの略で、「トータルで、1ファイル、2テストの実行を開始する」という意味となります。このメセージを処理し、正しくレポートを表示する責任はレポートスクリプトにあります。

振る舞い(Behavior)

テスト実行の振る舞いを記述しているのが、baut--test-behaviorになります。こちらは、テストの実行や終了、各種基本的なコマンド(runrun2など)を提供している機能になります。こちらも以下のようにすることでカスタマイズ可能です。

  • ファイル名「local--test-behavior」を以下のディレクトリのいずれかに設置します。探索は、1から優先的に行われます。
    1. コマンドを実行したディレクトリ
    2. テスト実行ディレクトリ/helpers
    3. baut/libexec
    4. baut/helpers

load--test-behaviorは、baut--test-behaviorの後にロードされます。例えば、skipで送られるメッセージは以下のようにオーバーライドしカスタマイズできます。

ダウンロード

GitHub - moritetu/baut: A testing tool run on Bash
A testing tool run on Bash. Contribute to moritetu/baut development by creating an account on GitHub.

Other Documentation

ライセンス(License)

タイトルとURLをコピーしました