[Linux] 用 shunit2 來做 shell script 的 unit testing

[Linux] 用 shunit2 來做 shell script 的 unit testing

老實說我以前是不寫 unit-testing 的,

反正要測試的程式碼就編譯好,直接在產品環境上面測試就行了,

不過當然這樣的缺點就是不容易測到所有的參數組合,

或是要測試一些錯誤處理的部分時,會比較麻煩,

可能就得改程式,或是用除錯器單步執行來改變執行的路徑…

 

不過最近在 python 的專案上已經很習慣用 pytest 這個 unit-testing framework,

尤其是 unit-testing 可以方便地測試某個函式各種輸入輸出,

這個特性非常的不錯~可以加快測試的速度~

因此今天在改一個 shell script 時,也很想用 unit-testing 來測一下某些函式~

找了一下,似乎 shunit2 是不少人推薦使用的,試用起來也蠻簡單~

 

1. 安裝 shunit2

到 shunit2 官網 就可以下載 shunit2,看是要直接抓 ZIP 檔,

還是用 git clone 下來都可以,像我是用 git clone:

git clone https://github.com/kward/shunit2.git

 

抓下來的 shunit2 目錄下有許多東西,主要的執行檔是在 shunit2/source/2.1/src/shunit2

 

2. 撰寫第一個 unit-testing 程式

shunit2/source/2.1/examples 目錄下有幾個測試的範例可以參考,

下面直接拿我寫的 unit-testing 程式來看看吧~

 

因為我要測試的函式是寫在 common.sh,所以一開始先用 . common.sh 讀進來,

接著你可以有一個 setUp() 和 tearDown() 函式,

如果有定義的話,就會在跑每一個 testXXX() 函式前先跑 setUp(),跑完後跑 tearDown(),

因此可以在裡面做一些變數或資料的初始化~

如果是想在跑第一個 testXXX() 前做整體的初始化,

可以用 oneTimeSetUp/oneTimeTearDown:

#!/bin/sh
UT_FOLDER="$(dirname "$0")"
. "${UT_FOLDER}/../common.sh"
oneTimeSetup()
{
PYTHON_BIN="python"
}

 

接著,把測試碼寫在 testXXX() 函式裡面,只要名稱開頭是 test 就行了,

所以 testGetFolder() 或是 test_get_folder() 這兩種風格都行~

在測試碼裡用像 assertEquals 就能測試兩個值是否相等,

test_get_backup_folder()
{
# DST_FOLDER is not set
unset DST_FOLDER
assertEquals "$(get_backup_folder)" ""
# DST_FOLDER is set with empty value
DST_FOLDER=""
assertEquals "$(get_backup_folder)" ""
# DST_FOLDER is set with non-empty value
DST_FOLDER=/var/log/dst
assertEquals "$(get_backup_folder)" "${DST_FOLDER}/backup"
}
test_compare_version()
{
assertEquals "$(compare_version 1.10.1000 1.2.1001)" "older"
assertEquals "$(compare_version 1.2.1000  1.2.1001)" "older"
assertEquals "$(compare_version 1.2.1002  1.2.1001)" "newer"
assertEquals "$(compare_version 1.3.1000  1.2.1001)" "newer"
assertEquals "$(compare_version 2.0.1000  1.2.1001)" "newer"
assertEquals "$(compare_version 2.2.1000  1.2.1001)" "newer"
assertEquals "$(compare_version 2.3.1000  1.2.1001)" "newer"
}

 

shunit2 提供了好幾種 assert 函式,

詳細的說明可以看一下 shunit2/source/2.1/doc/shunit2.txt,像是有 

  – assertEquals, assertNotEquals

  – assertNull, assertNotNull

  – assertTrue, assertFalse

意義應該都蠻直覺的,只有 assertNull 稍微讓人不確定 Null 指的是什麼,

不過其實就是看字串是否為空字串囉~

 

在這個 shell script 的最後面,要加上 . shunit2,

就能讀入 shunit2 並開始跑 unit-testing 囉:

# Load shunit2 to run unittesting
. "${UT_FOLDER}/../3rd_party/shunit2/src/shunit2"

 

完整的測試程式如下:

#!/bin/sh
UT_FOLDER="$(dirname "$0")"
. "${UT_FOLDER}/../common.sh"
oneTimeSetUp()
{
PYTHON_BIN="python"
}
test_get_backup_folder()
{
# DST_FOLDER is not set
unset DST_FOLDER
assertEquals "$(get_backup_folder)" ""
# DST_FOLDER is set with empty value
DST_FOLDER=""
assertEquals "$(get_backup_folder)" ""
# DST_FOLDER is set with non-empty value
DST_FOLDER=/var/log/dst
assertEquals "$(get_backup_folder)" "${DST_FOLDER}/backup"
}
test_compare_version()
{
assertEquals "$(compare_version 1.10.1000 1.2.1001)" "older"
assertEquals "$(compare_version 1.2.1000  1.2.1001)" "older"
assertEquals "$(compare_version 1.2.1002  1.2.1001)" "newer"
assertEquals "$(compare_version 1.3.1000  1.2.1001)" "newer"
assertEquals "$(compare_version 2.0.1000  1.2.1001)" "newer"
assertEquals "$(compare_version 2.2.1000  1.2.1001)" "newer"
assertEquals "$(compare_version 2.3.1000  1.2.1001)" "newer"
}
# Load shunit2 to run unittesting
. "${UT_FOLDER}/../3rd_party/shunit2/src/shunit2"

 

3. 執行 unit-testing 程式

將剛才的 shell script 儲存起來,假設是存成 test_common.sh,

那麼只要執行 sh test_common.sh 就能開始跑 unit-testing 了:

testuser@localhost ~/src $ sh unittest/test_common.sh
test_get_backup_folder
test_compare_version
Ran 2 tests.
OK

 

如果 assert 不成立的話,就會列出錯誤:

testuser@localhost ~/src $ sh unittest/test_common.sh
test_get_backup_folder
test_compare_version
ASSERT:expected:<newer> but was:<older>
Ran 2 tests.
FAILED (failures=1)

 

有了 shunit2 之後,shell script 也能輕鬆愉快的寫 unit-testing 了,

感覺真不錯呀~~^^/

 

(本頁面已被瀏覽過 1,235 次)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料