Javaコードのほかにいくつかのbashスクリプトが実行されているシステムがあります。壊れる可能性のあるすべてのものをテストしようとしていて、bashスクリプトが壊れる可能性があるので、テストしたいと思います。
問題は、bashスクリプトのテストが難しいことです。
bashスクリプトをテストする方法またはベストプラクティスはありますか?または、bashスクリプトの使用を中止して、テスト可能な代替ソリューションを探す必要がありますか?
Javaコードのほかにいくつかのbashスクリプトが実行されているシステムがあります。壊れる可能性のあるすべてのものをテストしようとしていて、bashスクリプトが壊れる可能性があるので、テストしたいと思います。
問題は、bashスクリプトのテストが難しいことです。
bashスクリプトをテストする方法またはベストプラクティスはありますか?または、bashスクリプトの使用を中止して、テスト可能な代替ソリューションを探す必要がありますか?
回答:
実際には、ボーンベースのシェルスクリプト用のxUnitベースの単体テストフレームワークであるshunit2があります。私自身は使用していませんが、チェックする価値があるかもしれません。
同様の質問が以前に尋ねられました:
ディスカッショングループから次の回答を得ました。
外部ファイルからプロシージャ(関数、名前が何であれ)をインポート(インクルードなど)することが可能です。それがテストスクリプトを作成するための鍵です。スクリプトを独立したプロシージャに分割し、実行中のスクリプトとテストスクリプトの両方にインポートできます。次に、実行中のスクリプトをできるだけシンプルにします。
この方法は、スクリプトの依存性注入に似ており、合理的に聞こえます。bashスクリプトを避け、テスト可能で曖昧でない言語を使用することをお勧めします。
TAP準拠のBashテスト:Bash自動テストシステム
TAP(テストエニーシングプロトコル)は、テストハーネス内のテストモジュール間の単純なテキストベースのインターフェースです。TAPはPerlのテストハーネスの一部として開始されましたが、現在はC、C ++、Python、PHP、Perl、Java、JavaScriptなどで実装されています。
Nikita Sobolevは、いくつかの異なるbashテストフレームワークを比較する優れたブログ投稿を書きました:Bashアプリケーションのテスト
せっかちな人のために:Nikitaの結論はBatsを使用することでしたが、Nikitaは、オリジナルのBatsプロジェクトが2013年以降積極的に維持されていないため、今後使用すると思われるBats-coreプロジェクトを逃したようです。
bashスクリプトをテストすることが「難しい」と言うのはなぜですか?
次のようなテストラッパーの何が問題になっています:
#!/bin/bash
set -e
errors=0
results=$($script_under_test $args<<ENDTSTDATA
# inputs
# go
# here
#
ENDTSTDATA
)
[ "$?" -ne 0 ] || {
echo "Test returned error code $?" 2>&1
let errors+=1
}
echo "$results" | grep -q $expected1 || {
echo "Test Failed. Expected $expected1"
let errors+=1
}
# and so on, et cetera, ad infinitum, ad nauseum
[ "$errors" -gt 0 ] && {
echo "There were $errors errors found"
exit 1
}
使いやすく便利なツールが欲しかったので、shellspecを作成しました。
純粋なPOSIXシェルスクリプトで記述されています。shunit2より多くのシェルでテストされています。bats / bats-coreより強力な機能があります。
たとえば、ネストされたブロック、モック/スタブが簡単、スキップ/保留が簡単、パラメーター化されたテスト、アサーション行番号、行番号ごとの実行、並列実行、ランダム実行、TAP / JUnitフォーマッター、カバレッジとCI統合、プロファイラーなどをサポートします。 。
プロジェクトページのデモを参照してください。
私はshell2junitがかなり好きです、BashスクリプトテストからJUnitのような出力を生成するユーティリティである。生成されたレポートは、JenkinsやBamboo用のJUnitプラグインなどの継続的インテグレーションシステムで読み取ることができるため、これは便利です。
shell2junitのような包括的なバッシュスクリプトフレームワークを提供しませんがshunit2を、それはあなたがテスト結果の素敵な報告を持って認めていません。
bashtestを試してください。スクリプトをテストする簡単な方法です。たとえば、do-some-work.sh
いくつかの設定ファイルを変更したとします。たとえば、PASSWORD = 'XXXXX'
設定ファイルに新しい行を追加します/etc/my.cfg
。
bashコマンドを1行ずつ記述してから、出力を確認します。
インストール:
pip3 install bashtest
テストの作成は、bashコマンドを記述するだけです。
ファイルtest-do-some-work.bashtest
:
# run the script
$ ./do-some-work.sh > /dev/null
# testing that the line "PASSWORD = 'XXXXX'" is in the file /etc/my.cfg
$ grep -Fxq "PASSWORD = 'XXXXX'" /etc/my.cfg && echo "YES"
YES
テストを実行します。
bashtest *.bashtest
あなたは見つけることができ、ここでいくつかの例をしてここに
多分これは使用できるか、または貢献することができます
https://thorsteinssonh.github.io/bash_test_tools/
TAPプロトコルで結果を書き込むことを目的としており、CIに適していること、およびシェル環境が必要なユーザーに適していることを想像してください。シェル環境で実行されるものがあると思いますので、シェル環境でテストする必要があると主張する人もいます。
assert.shを試してみてください
source "./assert.sh"
local expected actual
expected="Hello"
actual="World!"
assert_eq "$expected" "$actual" "not equivalent!"
# => x Hello == World :: not equivalent!
それが役に立てば幸い!
OSHTについて誰も話さなかったなんて信じられない!それは両方と互換性がありますTAPとJUnitのと純粋なシェル(つまり、他の言語は関与していません)であり、スタンドアロンでも動作し、シンプルで直接的です。
テストは次のようになります(プロジェクトページから抜粋したスニペット):
#!/bin/bash
. osht.sh
# Optionally, indicate number of tests to safeguard against abnormal exits
PLAN 13
# Comparing stuff
IS $(whoami) != root
var="foobar"
IS "$var" =~ foo
ISNT "$var" == foo
# test(1)-based tests
OK -f /etc/passwd
NOK -w /etc/passwd
# Running stuff
# Check exit code
RUNS true
NRUNS false
# Check stdio/stdout/stderr
RUNS echo -e 'foo\nbar\nbaz'
GREP bar
OGREP bar
NEGREP . # verify empty
# diff output
DIFF <<EOF
foo
bar
baz
EOF
# TODO and SKIP
TODO RUNS false
SKIP test $(uname -s) == Darwin
簡単な実行:
$ bash test.sh
1..13
ok 1 - IS $(whoami) != root
ok 2 - IS "$var" =~ foo
ok 3 - ISNT "$var" == foo
ok 4 - OK -f /etc/passwd
ok 5 - NOK -w /etc/passwd
ok 6 - RUNS true
ok 7 - NRUNS false
ok 8 - RUNS echo -e 'foo\nbar\nbaz'
ok 9 - GREP bar
ok 10 - OGREP bar
ok 11 - NEGREP . # verify empty
ok 12 - DIFF <<EOF
not ok 13 - TODO RUNS false # TODO Test Know to fail
最後のテストでは「問題あり」と表示されていますが、終了コードはであるため0 TODO
です。冗長を設定することもできます:
$ OSHT_VERBOSE=1 bash test.sh # Or -v
1..13
# dcsobral \!= root
ok 1 - IS $(whoami) != root
# foobar =\~ foo
ok 2 - IS "$var" =~ foo
# \! foobar == foo
ok 3 - ISNT "$var" == foo
# test -f /etc/passwd
ok 4 - OK -f /etc/passwd
# test \! -w /etc/passwd
ok 5 - NOK -w /etc/passwd
# RUNNING: true
# STATUS: 0
# STDIO <<EOM
# EOM
ok 6 - RUNS true
# RUNNING: false
# STATUS: 1
# STDIO <<EOM
# EOM
ok 7 - NRUNS false
# RUNNING: echo -e foo\\nbar\\nbaz
# STATUS: 0
# STDIO <<EOM
# foo
# bar
# baz
# EOM
ok 8 - RUNS echo -e 'foo\nbar\nbaz'
# grep -q bar
ok 9 - GREP bar
# grep -q bar
ok 10 - OGREP bar
# \! grep -q .
ok 11 - NEGREP . # verify empty
ok 12 - DIFF <<EOF
# RUNNING: false
# STATUS: 1
# STDIO <<EOM
# EOM
not ok 13 - TODO RUNS false # TODO Test Know to fail
.t
拡張機能を使用するように名前を変更してt
サブディレクトリに配置すると、prove(1)
(Perlの一部)を使用して実行できます。
$ prove
t/test.t .. ok
All tests successful.
Files=1, Tests=13, 0 wallclock secs ( 0.03 usr 0.01 sys + 0.11 cusr 0.16 csys = 0.31 CPU)
Result: PASS
JUnit出力を生成するために設定OSHT_JUNIT
または渡し-j
ます。JUnitはと組み合わせることもできprove(1)
ます。
私は自分のファイルを調達し、その後でアサーションを実行することで機能をテストし、両方のこのライブラリを使用しているIS
/ OK
利用して、そのネガ、およびスクリプトRUN
/をNRUN
。私にとって、このフレームワークは、最小限のオーバーヘッドで最大の利益をもたらします。
ここで紹介するソリューションの多くを試してみましたが、それらのほとんどがかさばって使いにくいことがわかったので、独自の小さなテストフレームワークを構築しました:https : //github.com/meonlol/t-bash
これは、JUnitスタイルアサートの基本セットを使用して、直接直接実行できるリポジトリ内の1つのファイルにすぎません。
私はいくつかの社内プロジェクトで専門的に使用しており、bashスクリプトを非常に安定して回帰に耐えることができました。
あなたはbash_unitを見てみたいかもしれません:
Outthenticを見てください。コマンドラインアプリケーションをテストするために、シンプルで多くの言語(Perl、Python、Ruby、Bashを選択可能)およびクロスプラットフォーム(Linux、Windows)フレームワークで拡張できます。
Pythonに次のような大きな利点がある場合、大きなスクリプトにbashを使用することを正当化するのは難しいと思いました。
if [ x"$foo" = x"$bar"]; then ...
エラーが発生しやすい '。getopt
モジュールます(解析するためのさらに簡単なモジュールがありますが、名前が私をエスケープします)。mysql
bash のコマンドにパイプできることを確認してください。ただし、コードを記述する最も良い方法ではありません)。$*
か、"$*"
または"$@"
または$1
または"$1"
、ファイル名にスペースの問題ではない、など、など、など現在、私は最も単純なスクリプトにのみbashを使用しています。
if [[ $foo = $bar ]]; then ...
。これはpythonが提供するものよりはまだ良くありませんが、あなたが提示したものよりは良いです。
trap
正規表現(つまり[[ $1 =~ ^[1-3]{3}$ ]]
)だけでなく(エラーが発生した場合のクリーンアップ/取り消しも)必要があります。あなたが使用したあいまいな構文はtest
、bashではなくの古い実装を参照していると確信しています。Bashは既存のコマンドラインツールとのインターフェースに最適です...多くの場合、単一のパイプを使用するawk
かgrep
、Pythonの代替ツールよりもはるかに簡単です。
optparse
またはその後継argparse
です。誰もgetopt
モジュールを使用したことはありませんし、個人的に使用したこともありません。getopt
しかし、ユーティリティは素晴らしいです。素敵なパターンを見つけたら、シェルからの引数の解析はまったく問題になりません。あなたがgitスタイルのサブコマンドか何かを実装しようとしているのでない限り、それは多くの問題ではありません。