新聞中心
Bash 自動(dòng)測(cè)試系統(tǒng)可以使 Bash 代碼也通過 Java、Ruby 和 Python 開發(fā)人員所使用的同類測(cè)試過程。
成都創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括華陰網(wǎng)站建設(shè)、華陰網(wǎng)站制作、華陰網(wǎng)頁制作以及華陰網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,華陰網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到華陰省份的部分城市,未來相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
用 Java、Ruby 和 Python 等語言編寫應(yīng)用程序的軟件開發(fā)人員擁有復(fù)雜的庫,可以幫助他們隨著時(shí)間的推移保持軟件的完整性。他們可以創(chuàng)建測(cè)試,以在結(jié)構(gòu)化環(huán)境中通過執(zhí)行一系列動(dòng)作來運(yùn)行應(yīng)用程序,以確保其軟件所有的方面均按預(yù)期工作。
當(dāng)這些測(cè)試在持續(xù)集成(CI)系統(tǒng)中自動(dòng)進(jìn)行時(shí),它們的功能就更加強(qiáng)大了,每次推送到源代碼庫都會(huì)觸發(fā)測(cè)試,并且在測(cè)試失敗時(shí)會(huì)立即通知開發(fā)人員。這種快速反饋提高了開發(fā)人員對(duì)其應(yīng)用程序功能完整性的信心。
Bash 自動(dòng)測(cè)試系統(tǒng)Bash Automated Testing System(BATS)使編寫 Bash 腳本和庫的開發(fā)人員能夠?qū)?Java、Ruby、Python 和其他開發(fā)人員所使用的相同慣例應(yīng)用于其 Bash 代碼中。
安裝 BATS
BATS GitHub 頁面包含了安裝指令。有兩個(gè) BATS 輔助庫提供更強(qiáng)大的斷言或允許覆寫 BATS 使用的 Test Anything Protocol(TAP)輸出格式。這些庫可以安裝在一個(gè)標(biāo)準(zhǔn)位置,并被所有的腳本引用。更方便的做法是,將 BATS 及其輔助庫的完整版本包含在 Git 倉庫中,用于要測(cè)試的每組腳本或庫。這可以通過 git 子模塊 系統(tǒng)來完成。
以下命令會(huì)將 BATS 及其輔助庫安裝到 Git 知識(shí)庫中的 test 目錄中。
git submodule initgit submodule add https://github.com/sstephenson/bats test/libs/batsgit submodule add https://github.com/ztombol/bats-assert test/libs/bats-assertgit submodule add https://github.com/ztombol/bats-support test/libs/bats-supportgit add .git commit -m 'installed bats'
要克隆 Git 倉庫并同時(shí)安裝其子模塊,請(qǐng)?jiān)?nbsp;git clone 時(shí)使用 --recurse-submodules 標(biāo)記。
每個(gè) BATS 測(cè)試腳本必須由 bats 可執(zhí)行文件執(zhí)行。如果你將 BATS 安裝到源代碼倉庫的 test/libs 目錄中,則可以使用以下命令調(diào)用測(cè)試:
./test/libs/bats/bin/bats <測(cè)試腳本的路徑>
或者,將以下內(nèi)容添加到每個(gè) BATS 測(cè)試腳本的開頭:
#!/usr/bin/env ./test/libs/bats/bin/batsload 'libs/bats-support/load'load 'libs/bats-assert/load'
并且執(zhí)行命令 chmod +x <測(cè)試腳本的路徑>。 這將 a、使它們可與安裝在 ./test/libs/bats 中的 BATS 一同執(zhí)行,并且 b、包含這些輔助庫。BATS 測(cè)試腳本通常存儲(chǔ)在 test 目錄中,并以要測(cè)試的腳本命名,擴(kuò)展名為 .bats。例如,一個(gè)測(cè)試 bin/build 的 BATS 腳本應(yīng)稱為 test/build.bats。
你還可以通過向 BATS 傳遞正則表達(dá)式來運(yùn)行一整套 BATS 測(cè)試文件,例如 ./test/lib/bats/bin/bats test/*.bats。
為 BATS 覆蓋率而組織庫和腳本
Bash 腳本和庫必須以一種有效地方式將其內(nèi)部工作原理暴露給 BATS 進(jìn)行組織。通常,在調(diào)用或執(zhí)行時(shí)庫函數(shù)和運(yùn)行諸多命令的 Shell 腳本不適合進(jìn)行有效的 BATS 測(cè)試。
例如,build.sh 是許多人都會(huì)編寫的典型腳本。本質(zhì)上是一大堆代碼。有些人甚至可能將這堆代碼放入庫中的函數(shù)中。但是,在 BATS 測(cè)試中運(yùn)行一大堆代碼,并在單獨(dú)的測(cè)試用例中覆蓋它可能遇到的所有故障類型是不可能的。測(cè)試這堆代碼并有足夠的覆蓋率的唯一方法就是把它分解成許多小的、可重用的、最重要的是可獨(dú)立測(cè)試的函數(shù)。
向庫添加更多的函數(shù)很簡(jiǎn)單。額外的好處是其中一些函數(shù)本身可以變得出奇的有用。將庫函數(shù)分解為許多較小的函數(shù)后,你可以在 BATS 測(cè)試中援引source這些庫,并像測(cè)試任何其他命令一樣運(yùn)行這些函數(shù)。
Bash 腳本也必須分解為多個(gè)函數(shù),執(zhí)行腳本時(shí),腳本的主要部分應(yīng)調(diào)用這些函數(shù)。此外,還有一個(gè)非常有用的技巧,可以讓你更容易地用 BATS 測(cè)試 Bash 腳本:將腳本主要部分中執(zhí)行的所有代碼都移到一個(gè)函數(shù)中,稱為 run_main。然后,將以下內(nèi)容添加到腳本的末尾:
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]thenrun_mainfi
這段額外的代碼做了一些特別的事情。它使腳本在作為腳本執(zhí)行時(shí)與使用援引source進(jìn)入環(huán)境時(shí)的行為有所不同。通過援引并測(cè)試單個(gè)函數(shù),這個(gè)技巧使得腳本的測(cè)試方式和庫的測(cè)試方式變得一樣。例如,這是重構(gòu)的 build.sh,以獲得更好的 BATS 可測(cè)試性。
編寫和運(yùn)行測(cè)試
如上所述,BATS 是一個(gè) TAP 兼容的測(cè)試框架,其語法和輸出對(duì)于使用過其他 TAP 兼容測(cè)試套件(例如 JUnit、RSpec 或 Jest)的用戶來說將是熟悉的。它的測(cè)試被組織成單個(gè)測(cè)試腳本。測(cè)試腳本被組織成一個(gè)或多個(gè)描述性 @test 塊中,它們描述了被測(cè)試應(yīng)用程序的單元。每個(gè) @test 塊將運(yùn)行一系列命令,這些命令準(zhǔn)備測(cè)試環(huán)境、運(yùn)行要測(cè)試的命令,并對(duì)被測(cè)試命令的退出和輸出進(jìn)行斷言。許多斷言函數(shù)是通過 bats、bats-assert 和 bats-support 庫導(dǎo)入的,這些庫在 BATS 測(cè)試腳本的開頭加載到環(huán)境中。下面是一個(gè)典型的 BATS 測(cè)試塊:
@test "requires CI_COMMIT_REF_SLUG environment variable" {unset CI_COMMIT_REF_SLUGassert_empty "${CI_COMMIT_REF_SLUG}"run some_commandassert_failureassert_output --partial "CI_COMMIT_REF_SLUG"}
如果 BATS 腳本包含 setup(安裝)和/或 teardown(拆卸) 函數(shù),則 BATS 將在每個(gè)測(cè)試塊運(yùn)行之前和之后自動(dòng)執(zhí)行它們。這樣就可以創(chuàng)建環(huán)境變量、測(cè)試文件以及執(zhí)行一個(gè)或所有測(cè)試所需的其他操作,然后在每次測(cè)試運(yùn)行后將其拆卸。Build.bats 是對(duì)我們新格式化的 build.sh 腳本的完整 BATS 測(cè)試。(此測(cè)試中的 mock_docker 命令將在以下關(guān)于模擬/打標(biāo)的部分中進(jìn)行說明。)
當(dāng)測(cè)試腳本運(yùn)行時(shí),BATS 使用 exec(執(zhí)行)來將每個(gè) @test 塊作為單獨(dú)的子進(jìn)程運(yùn)行。這樣就可以在一個(gè) @test 中導(dǎo)出環(huán)境變量甚至函數(shù),而不會(huì)影響其他 @test 或污染你當(dāng)前的 Shell 會(huì)話。測(cè)試運(yùn)行的輸出是一種標(biāo)準(zhǔn)格式,可以被人理解,并且可以由 TAP 使用端以編程方式進(jìn)行解析或操作。下面是 CI_COMMIT_REF_SLUG 測(cè)試塊失敗時(shí)的輸出示例:
requires CI_COMMIT_REF_SLUG environment variable(from function `assert_output' in file test/libs/bats-assert/src/assert.bash, line 231,in test file test/ci_deploy.bats, line 26)`assert_output --partial "CI_COMMIT_REF_SLUG"' failed-- output does not contain substring --substring (1 lines):CI_COMMIT_REF_SLUGoutput (3 lines):./bin/deploy.sh: join_string_by: command not foundoc errorCould not login--** Did not delete , as test failed **1 test, 1 failure
下面是成功測(cè)試的輸出:
requires CI_COMMIT_REF_SLUG environment variable
輔助庫
像任何 Shell 腳本或庫一樣,BATS 測(cè)試腳本可以包括輔助庫,以在測(cè)試之間共享通用代碼或增強(qiáng)其性能。這些輔助庫,例如 bats-assert 和 bats-support 甚至可以使用 BATS 進(jìn)行測(cè)試。
庫可以和 BATS 腳本放在同一個(gè)測(cè)試目錄下,如果測(cè)試目錄下的文件數(shù)量過多,也可以放在 test/libs 目錄下。BATS 提供了 load 函數(shù),該函數(shù)接受一個(gè)相對(duì)于要測(cè)試的腳本的 Bash 文件的路徑(例如,在我們的示例中的 test),并援引該文件。文件必須以后綴 .bash 結(jié)尾,但是傳遞給 load 函數(shù)的文件路徑不能包含后綴。build.bats 加載 bats-assert 和 bats-support 庫、一個(gè)小型 helpers.bash 庫以及 docker_mock.bash 庫(如下所述),以下代碼位于測(cè)試腳本的開頭,解釋器魔力行下方:
load 'libs/bats-support/load'load 'libs/bats-assert/load'load 'helpers'load 'docker_mock'
打標(biāo)測(cè)試輸入和模擬外部調(diào)用
大多數(shù) Bash 腳本和庫運(yùn)行時(shí)都會(huì)執(zhí)行函數(shù)和/或可執(zhí)行文件。通常,它們被編程為基于這些函數(shù)或可執(zhí)行文件的輸出狀態(tài)或輸出(stdout、stderr)以特定方式運(yùn)行。為了正確地測(cè)試這些腳本,通常需要制作這些命令的偽版本,這些命令被設(shè)計(jì)成在特定測(cè)試過程中以特定方式運(yùn)行,稱為“打標(biāo)stubbing”。可能還需要監(jiān)視正在測(cè)試的程序,以確保其調(diào)用了特定命令,或者使用特定參數(shù)調(diào)用了特定命令,此過程稱為“模擬mocking”。有關(guān)更多信息,請(qǐng)查看在 Ruby RSpec 中 有關(guān)模擬和打標(biāo)的討論,它適用于任何測(cè)試系統(tǒng)。
Bash shell 提供了一些技巧,可以在你的 BATS 測(cè)試腳本中使用這些技巧進(jìn)行模擬和打標(biāo)。所有這些都需要使用帶有 -f 標(biāo)志的 Bash export 命令來導(dǎo)出一個(gè)覆蓋了原始函數(shù)或可執(zhí)行文件的函數(shù)。必須在測(cè)試程序執(zhí)行之前完成此操作。下面是重寫可執(zhí)行命令 cat 的簡(jiǎn)單示例:
function cat() { echo "THIS WOULD CAT ${*}" }export -f cat
此方法以相同的方式覆蓋了函數(shù)。如果一個(gè)測(cè)試需要覆蓋要測(cè)試的腳本或庫中的函數(shù),則在對(duì)函數(shù)進(jìn)行打標(biāo)或模擬之前,必須先聲明已測(cè)試腳本或庫,這一點(diǎn)很重要。否則,在聲明腳本時(shí),打標(biāo)/模擬將被原函數(shù)替代。另外,在運(yùn)行即將進(jìn)行的測(cè)試命令之前確認(rèn)打標(biāo)/模擬。下面是build.bats 的示例,該示例模擬 build.sh 中描述的raise 函數(shù),以確保登錄函數(shù)會(huì)引發(fā)特定的錯(cuò)誤消息:
@test ".login raises on oc error" {source ${profile_script}function raise() { echo "${1} raised"; }export -f raiserun loginassert_failureassert_output -p "Could not login raised"}
一般情況下,沒有必要在測(cè)試后復(fù)原打標(biāo)/模擬的函數(shù),因?yàn)?nbsp;export(輸出)僅在當(dāng)前 @test 塊的 exec(執(zhí)行)期間影響當(dāng)前子進(jìn)程。但是,可以模擬/打標(biāo) BATS assert 函數(shù)在內(nèi)部使用的命令(例如 cat、sed 等)是可能的。在運(yùn)行這些斷言命令之前,必須對(duì)這些模擬/打標(biāo)函數(shù)進(jìn)行 unset(復(fù)原),否則它們將無法正常工作。下面是 build.bats 中的一個(gè)示例,該示例模擬 sed,運(yùn)行 build_deployable 函數(shù)并在運(yùn)行任何斷言之前復(fù)原 sed:
@test ".build_deployable prints information, runs docker build on a modified Dockerfile.production and publish_image when its not a dry_run" {local expected_dockerfile='Dockerfile.production'local application='application'local environment='environment'local expected_original_base_image="${application}"local expected_candidate_image="${application}-candidate:${environment}"local expected_deployable_image="${application}:${environment}"source ${profile_script}mock_docker build --build-arg OAUTH_CLIENT_ID --build-arg OAUTH_REDIRECT --build-arg DDS_API_BASE_URL -t "${expected_deployable_image}" -function publish_image() { echo "publish_image ${*}"; }export -f publish_imagefunction sed() {echo "sed ${*}" >&2;echo "FROM application-candidate:environment";}export -f sedrun build_deployable "${application}" "${environment}"assert_successunset sedassert_output --regexp "sed.*${expected_dockerfile}"assert_output -p "Building ${expected_original_base_image} deployable ${expected_deployable_image} FROM ${expected_candidate_image}"assert_output -p "FROM ${expected_candidate_image} piped"assert_output -p "build --build-arg OAUTH_CLIENT_ID --build-arg OAUTH_REDIRECT --build-arg DDS_API_BASE_URL -t ${expected_deployable_image} -"assert_output -p "publish_image ${expected_deployable_image}"}
有的時(shí)候相同的命令,例如 foo,將在被測(cè)試的同一函數(shù)中使用不同的參數(shù)多次調(diào)用。這些情況需要?jiǎng)?chuàng)建一組函數(shù):
mock_foo:將期望的參數(shù)作為輸入,并將其持久化到 TMP 文件中foo:命令的模擬版本,該命令使用持久化的預(yù)期參數(shù)列表處理每個(gè)調(diào)用。必須使用export -f將其導(dǎo)出。cleanup_foo:刪除 TMP 文件,用于拆卸函數(shù)。這可以進(jìn)行測(cè)試以確保在刪除之前成功完成@test塊。
由于此功能通常在不同的測(cè)試中重復(fù)使用,因此創(chuàng)建一個(gè)可以像其他庫一樣加載的輔助庫會(huì)變得有意義。
docker_mock.bash 是一個(gè)很棒的例子。它被加載到 build.bats 中,并在任何測(cè)試調(diào)用 Docker 可執(zhí)行文件的函數(shù)的測(cè)試塊中使用。使用 docker_mock 典型的測(cè)試塊如下所示:
@test ".publish_image fails if docker push fails" {setup_publishlocal expected_image="image"local expected_publishable_image="${CI_REGISTRY_IMAGE}/${expected_image}"source ${profile_script}mock_docker tag "${expected_image}" "${expected_publishable_image}"mock_docker push "${expected_publishable_image}" and_failrun publish_image "${expected_image}"assert_failureassert_output -p "tagging ${expected_image} as ${expected_publishable_image}"assert_output -p "tag ${expected_image} ${expected_publishable_image}"assert_output -p "pushing image to gitlab registry"assert_output -p "push ${expected_publishable_image}"}
該測(cè)試建立了一個(gè)使用不同的參數(shù)兩次調(diào)用 Docker 的預(yù)期。在對(duì)Docker 的第二次調(diào)用失敗時(shí),它會(huì)運(yùn)行測(cè)試命令,然后測(cè)試退出狀態(tài)和對(duì) Docker 調(diào)用的預(yù)期。
一方面 BATS 利用 mock_docker.bash 引入 ${BATS_TMPDIR} 環(huán)境變量,BATS 在測(cè)試開始的位置對(duì)其進(jìn)行了設(shè)置,以允許測(cè)試和輔助程序在標(biāo)準(zhǔn)位置創(chuàng)建和銷毀 TMP 文件。如果測(cè)試失敗,mock_docker.bash 庫不會(huì)刪除其持久化的模擬文件,但會(huì)打印出其所在位置,以便可以查看和刪除它。你可能需要定期從該目錄中清除舊的模擬文件。
關(guān)于模擬/打標(biāo)的一個(gè)注意事項(xiàng):build.bats 測(cè)試有意識(shí)地違反了關(guān)于測(cè)試聲明的規(guī)定:不要模擬沒有擁有的! 該規(guī)定要求調(diào)用開發(fā)人員沒有編寫代碼的測(cè)試命令,例如 docker、cat、sed 等,應(yīng)封裝在自己的庫中,應(yīng)在使用它們腳本的測(cè)試中對(duì)其進(jìn)行模擬。然后應(yīng)該在不模擬外部命令的情況下測(cè)試封裝庫。
這是一個(gè)很好的建議,而忽略它是有代價(jià)的。如果 Docker CLI API 發(fā)生變化,則測(cè)試腳本不會(huì)檢測(cè)到此變化,從而導(dǎo)致錯(cuò)誤內(nèi)容直到經(jīng)過測(cè)試的 build.sh 腳本在使用新版本 Docker 的生產(chǎn)環(huán)境中運(yùn)行后才顯示出來。測(cè)試開發(fā)人員必須確定要嚴(yán)格遵守此標(biāo)準(zhǔn)的程度,但是他們應(yīng)該了解其所涉及的權(quán)衡。
總結(jié)
在任何軟件開發(fā)項(xiàng)目中引入測(cè)試制度,都會(huì)在以下兩方面產(chǎn)生權(quán)衡: a、增加開發(fā)和維護(hù)代碼及測(cè)試所需的時(shí)間和組織,b、增加開發(fā)人員在對(duì)應(yīng)用程序整個(gè)生命周期中完整性的信心。測(cè)試制度可能不適用于所有腳本和庫。
通常,滿足以下一個(gè)或多個(gè)條件的腳本和庫才可以使用 BATS 測(cè)試:
- 值得存儲(chǔ)在源代碼管理中
- 用于關(guān)鍵流程中,并依靠它們長(zhǎng)期穩(wěn)定運(yùn)行
- 需要定期對(duì)其進(jìn)行修改以添加/刪除/修改其功能
- 可以被其他人使用
一旦決定將測(cè)試規(guī)則應(yīng)用于一個(gè)或多個(gè) Bash 腳本或庫,BATS 就提供其他軟件開發(fā)環(huán)境中可用的全面測(cè)試功能。
致謝:感謝 Darrin Mann 向我引薦了 BATS 測(cè)試。
網(wǎng)站欄目:利用BATS測(cè)試Bash腳本和庫
網(wǎng)頁URL:http://www.dlmjj.cn/article/djsgdhh.html


咨詢
建站咨詢

