本文分析了bats--Bash自動化測試工具的安裝、語法、經常使用指令及經常使用函數等內容。
上篇文章回顧: 學習RAID 01/10/10E的區別
bats 是一個符合 TAP 標準 的 Bash 版測試框架,它使用了一種極爲簡便的方法來驗證命令行程序是否正常運行。git
bats 要求 Bash 的最低版本是 3.2.57 ,bats 測試文件實際上一個 bash 的腳本文件,徹底可使用 shell 的語法書寫。github
強烈建議使用源碼或者npm安裝最新版本, bats 通過多人接手,代碼存放比較混亂,某些系統下安裝的是舊版本的,目前社區在維護的版本地址爲:正則表達式
https://github.com/bats-core/bats-core.git
docker
brew install bats-core複製代碼
yum install bats複製代碼
apt-get install bats複製代碼
Git for Windows Bash (MSYS2 based)shell
Windows Subsystem for Linuxnpm
MSYS2ubuntu
Cygwin數組
Windows下推薦使用源碼安裝或者 npm 的方式進行安裝。bash
git clone https://github.com/bats-core/bats-core.gitcd bats-core
./install.sh /usr/local
複製代碼
docker pull bats/bats
docker run -it --rm bats/bats --version
docker run -it --rm -v "$(pwd):/code" bats/bats /code/test複製代碼
npm install -g bats
複製代碼
通過測試 CentOS 下的版本爲 2014 年的版本,ubuntu下也不是最新版本,建議使用源碼或者npm安裝最新版本。
框架
測試用例的語法格式爲:
#!/usr/bin/env bats@test "grep --version check" { # 測試用例名稱
run grep --version # 運行的外部命令
[ $status -eq 0 ] # 斷言
[ "${lines[0]%% *}" == 'grep' ] # 斷言
}複製代碼
每一個 Bats 測試文件的評估次數爲 n + 1 次,其中 n 是文件中的測試用例數。運行測試腳本時首先計算測試用例的數量,而後遍歷測試用例並在獨立進程中執行每一個測試用例。
在運行測試用例時,Bats使用Bash的 errexit(set -e)選項,這樣寫在@test 裏面的語句都是真理斷言。一旦測試用例中的某一個斷言失敗(某條語句的狀態碼不是 0)則這個測試用例視爲失敗。
用於測試外部命令而後對它的退出狀態和輸出狀態進行斷言。Bats 包含一個 run 的指令,它能夠將傳入的參數當成命令調用,而且將退出狀態和輸出狀態保存到特殊的全局變量中,以即可以繼續在測試用例中增長斷言。
好比說咱們正在測試 cat:
#!/usr/bin/env bats@test "cat nonexistent_filename check" { # 測試用例名稱
run cat nonexistent_filename # 運行的外部命令
[ $status -eq 1 ] # 斷言
[ "$output" == 'cat: nonexistent_filename: No such file or directory' ] # 斷言
[ "${lines[0]}" == 'cat: nonexistent_filename: No such file or directory' ] # 斷言
}複製代碼
這裏有三個 Bats 的特殊變量
$status 是命令退出狀態碼
$output 是命令的標準輸出和標準錯誤的內容
$lines是命令輸出內容的數組包含各行內容 cat nonexistent_filename 只有一行內容
若是想用跨越多個測試文件共享環境變量或者自定義的函數,可使用 load 指令。共享文件的擴展文件名必須是.bash。load可使用相對路徑或者絕對路徑。
使用相對路徑的寫法是(能夠省略擴展文件名):
load test_helper複製代碼
使用絕對路徑的寫法時(必須帶上擴展文件名):
load /test_helpers/test_helper.bash複製代碼
在測試過程當中若是失敗時若是想繼續能夠 skip 指令來跳過測試:
@test "A test I don't want to execute for now" {
skip
run foo
[ "$status" -eq 0 ]
}複製代碼
也能夠加入跳過緣由:
@test "A test I don't want to execute for now" {
skip "This command will return zero soon, but not now"
run foo
[ "$status" -eq 0 ]
}複製代碼
或者也能夠根據條件判斷是否跳過:
@test "A test which should run" { if [ foo != bar ]; then
skip "foo isn't bar"
fi
run foo
[ "$status" -eq 0 ]
}複製代碼
這是 Bats 主要的函數全部的測試用例都要按照這個函數的格式書寫:
@test "grep --version check" { # 測試用例名稱
run grep --version # 運行的外部命令
[ $status -eq 0 ] # 斷言
[ "${lines[0]%% *}" == 'grep' ] # 斷言
}複製代碼
setup / teardown 是兩個特殊的函數,用於在測試用例開始以前和結束以後進行初始化和藹後工做。好比開始以前設置環境變量建立測試目錄。以 soar 爲測試用例爲例:
setup() {
export SOAR_DEV_DIRNAME="${BATS_TEST_DIRNAME}/../"
export SOAR_BIN="${SOAR_DEV_DIRNAME}/bin/soar"
export SOAR_BIN_ENV="${SOAR_DEV_DIRNAME}/bin/soar -config ${SOAR_DEV_DIRNAME}/etc/soar.yaml"
export BATS_TMP_DIRNAME="${BATS_TEST_DIRNAME}/tmp"
export BATS_FIXTURE_DIRNAME="${BATS_TEST_DIRNAME}/fixture"
mkdir -p "${BATS_TMP_DIRNAME}"}
teardown(){ //TODO
......
}複製代碼
Bats 中包含幾個全局變量 :
$BATS_TEST_FILENAME Bats測試文件的絕對路徑。
$BATS_TEST_DIRNAME Bats測試文件所在的目錄。
$BATS_TEST_NAMES 每一個測試用例的函數名稱數組。
$BATS_TEST_NAME 包含當前測試用例的函數的名稱。
$BATS_TEST_DESCRIPTION 當前測試用例的描述。
$BATS_TEST_NUMBER 測試文件中當前測試用例的(從1開始)索引。
$BATS_TMPDIR 用於存儲臨時文件的目錄的位置。
寫在 @test 函數以外代碼一旦失敗 Bats 會馬上中斷執行,某些狀況下這樣作會頗有用好比檢查依賴項,可是若是在@test、setup、teardown以外打印的任何輸出必須重定向到stderr(>&2),不然這些輸出內容可能會污染TAP流致使Bats 測試失敗。
通過測試 @test 以外的代碼會優先執行
若是Bats卡死能夠讀這一塊內容。
Bats 將測試代碼的輸出流和 TAP 輸出流分開,這樣作的目的是爲了確保 TAP 的輸出不被污染。在輸出至終端的部分詳細介紹瞭如何使用 FD3 正確打印自定義文本。
可是使用 FD3 的一個已知的問題是:在某些狀況下(如程序的子進程在後臺運行的時候),它會致使 Bats 卡死。在這種狀況下在生成子進程的時候,子進程會從父進程繼承 FD3 ,致使Bats 會等待子進程執行完成以後關閉 FD3 。若是子進程須要花費大量時間完成,例如,若是子進程是 sleep 100 命令或是後臺服務,那麼 Bats 也會阻塞一樣的時間。
爲了不這種狀況,啓動可能長時間運行的子進程以前顯式關閉 FD3 command_name 3>&-
舉例說明:
1.會卡死的狀況:
@test "cat nonexistent_filename check" { # 測試用例名稱
run cat nonexistent_filename
sleep 100 & # 後臺執行
[ $status -eq 1 ]
[ "$TTTT" -eq 1 ] # 斷言
[ "$output" == 'cat: nonexistent_filename: No such file or directory' ] # 斷言
}複製代碼
2. 不會卡死的狀況:
@test "cat nonexistent_filename check" { # 測試用例名稱
run cat nonexistent_filename
sleep 100 3>&- & # 後臺執行而且關閉文件描述符3
[ $status -eq 1 ]
[ "$TTTT" -eq 1 ] # 斷言
[ "$output" == 'cat: nonexistent_filename: No such file or directory' ] # 斷言
}複製代碼
在 @test 函數內部輸出
(1)若是從@test 內部輸出字符你須要將輸出重定向到 FD3 例如 echo 'test'>&3。這時輸出將變成 TAP 流的一部分。爲了生成100%符合 TAP 流格式的輸出,咱們推薦的寫法是 echo '# text' >&3 。不然,在使用分析 TAP 流的第三方工具時可能會遇到意外錯誤。
(2)Bats 默認使用友好的輸出格式(-p, --pretty)。 TAP 流默認不會從 FD3 中輸出任何字符
(3)不管指定何種輸出格式,直接輸出到 stdout、stderr 的文本(例如 echo "aaaa")會被@test 視爲測試的一部分,僅僅在測試失敗的時候顯示。
在 setup/teardown 函數內部輸出
這一部份內容輸出行爲和@test 中同樣。
在 @test 或者setup/teardown 外部輸出
(1)不管輸出的字符被重定向到何處(FD一、FD二、FD3)字符都會馬上顯示到終端
(2)按照這種方式打印的文本將會禁用友好的輸出格式(-p, --pretty)。此外他也會使得輸出不符合 TAP 流規範。
(3)由內部管道或者重定向輸出到標準錯誤的字符總會第一時間顯示出來。
bats 命令行用法:
Bats 1.1.0 Usage: bats [-cr] [-f <regex>] [-p | -t] <test>...
bats [-h | -v]
<test> 爲一個 bats 測試用例的文件,或者是一個包含後綴名爲 .bats 文件的目錄
-c, --count 計算沒有運行的測試用例的個數
-f, --filter 經過正則表達式指定運行某些測試用例
-h, --help 顯示幫助信息
-p, --pretty 以比較友好的方式展示測試用例的輸出結果(默認是使用這種方式)
-r, --recursive 在子目錄中包含測試
-t, --tap 以 TAP 格式顯示輸出結果
-v, --version 顯示版本號信息複製代碼
更多信息見:
https://github.com/bats-core/bats-core複製代碼
在經常使用的開發工具中安裝 Bats 插件,增長代碼高亮顯示和代碼完成提示,提升開發效率。
更多開發工具和插件參考:
bats-core:
Bat Evaluation Process:
本文首發於公衆號」小米運維「,點擊查看原文。