成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

測試用例難寫?來試試 Sharness

開發 開發工具
Sharness 是一個用 Shell 腳本來編寫測試用例的測試框架。本文將詳細介紹 Sharness 的結構及測試用例的編寫格式,以及語法規范和技巧,教大家如何使用 Sharness 編寫測試用例,同時參與過 Git 項目的測試用例開發,為其測試框架的簡潔、高效而折服。

Sharness 是一個用 Shell 腳本來編寫測試用例的測試框架。本文將詳細介紹 Sharness 的結構及測試用例的編寫格式,以及語法規范和技巧,教大家如何使用 Sharness 編寫測試用例,同時參與過 Git 項目的測試用例開發,為其測試框架的簡潔、高效而折服。曾經嘗試將 Git 測試用例用于其他項目:《復用 git.git 測試框架》[1]。不過從 Git 項目中剝離測試用例框架還是挺費事的。

一次偶然的機會發現已經有人(Christian Couder:Gitlab 工程師,Git項目的領導委員會成員之一)已經將 Git 的測試用例框架剝離出來, 成為獨立的開源項目 Sharness。

有了 Sharness,寫測試用例不再是苦差事。

一 Sharness 是什么?

  • Sharness 是一個用 Shell 腳本來編寫測試用例的測試框架。
  • 可以在 Linux、macOS 平臺運行測試用例。
  • 測試輸出符合 TAP(test anything protocol),因此可以用 sharness 自身工具或 prove 等 TAP 兼容測試夾具(harness)運行。
  • 是由Junio在2005年為Git項目開發的測試框架,由 Christian Couder (chriscool) 從 Git 中剝離為獨立測試框架。
  • 地址:https://github.com/chriscool/sharness

二 Sharness 測試框架的優點

簡潔

如果要在測試用例中創建/初始化一個文件(內容為 “Hello, world.”), 看看 sharness 實現起來有多么簡單:

cat >expect <<-EOF 
Hello, world.
EOF

如果要對某應用(hello-world)的輸出和預期的 expect 文件進行比較, 相同則測試用例通過,不同則展示差異。測試用例編寫如下:

test_expect_success “app output test” ‘ 
cat >expect <<-EOF &&
Hello, world.
EOF
hello-world >actual &&
test_cmp expect actual

調試方便

每個測試用例腳本可以單獨執行。使用 -v 參數,可以顯示詳細輸出。使用 -d 參數,運行結束后保留用例的臨時目錄。

可以在要調試的test case后面增加 test_pause 語句,例如:

test_expect_success “name” ‘ 
<Script…>


test_pause
test_done

然后使用 -v 參數運行該腳本,會在 test_pause 語句處中斷,進入一個包含 sharness 環境變量的子 Shell 中,目錄會切換到測試用例單獨的工作區。調試完畢退出 Shell 即返回。

三 Git 項目的測試框架結構

Sharness 源自于 Git 項目的測試用例框架。我們先來看看 Git 項目測試框架的結構。

Git 項目測試相關文件

  • 待測應用放在項目的根目錄。例如 Git 項目的待測應用: git 和 git-receive-pack 等。
  • 測試框架修改 PATH 環境變量,使得測試用例在調用待測應用(如 git 命令)的時候,優先使用項目根目錄下的待測應用。
  • 測試腳本命名為 tNNNN-.sh,即以字母 t 和四位數字開頭的腳本文件。
  • 每一個測試用例在執行時會創建一個獨立的臨時目錄,例如 trash directory.t5323-pack-redundant。測試用例執行成功,則該目錄會被刪除。

相關代碼參見[2]。

四 Git 測試腳本的格式

以如下測試腳本為例[3]:

(1)在文件頭,定義 test_description 變量,提供測試用例的簡單說明,通常使用一行文本。本測試用例較為復雜,使用了多行文本進行描述。

#!/bin/sh 
#
# Copyright (c) 2018 Jiang Xin
#

test_description='Test git pack-redundant

In order to test git-pack-redundant, we will create a number of objects and
packs in the repository `master.git`. The relationship between packs (P1-P8)
and objects (T, A-R) is showed in the following chart. Objects of a pack will
be marked with letter x, while objects of redundant packs will be marked with
exclamation point, and redundant pack itself will be marked with asterisk.

| T A B C D E F G H I J K L M N O P Q R
----+--------------------------------------
P1 | x x x x x x x x
P2* | ! ! ! ! ! ! !
P3 | x x x x x x
P4* | ! ! ! ! !
P5 | x x x x
P6* | ! ! !
P7 | x x
P8* | !
----+--------------------------------------
ALL | x x x x x x x x x x x x x x x x x x x

Another repository `shared.git` has unique objects (X-Z), while other objects
(marked with letter s) are shared through alt-odb (of `master.git`). The
relationship between packs and objects is as follows:

| T A B C D E F G H I J K L M N O P Q R X Y Z
----+----------------------------------------------
Px1 | s s s x x x
Px2 | s s s x x x
'

(2)包含測試框架代碼。

. ./test-lib.sh

(3)定義全局變量,以及定義要在測試用例中用到的函數封裝。

master_repo=master.git 
shared_repo=shared.git

# Create commits in <repo> and assign each commit's oid to shell variables
# given in the arguments (A, B, and C). E.g.:
#
# create_commits_in <repo> A B C
#
# NOTE: Avoid calling this function from a subshell since variable
# assignments will disappear when subshell exits.
create_commits_in () {
repo="$1" &&
if ! parent=$(git -C "$repo" rev-parse HEAD^{} 2>/dev/null)
then
... ...

(4)用 test_expect_success 等方法撰寫測試用例。

test_expect_success 'setup master repo' ' 
git init --bare "$master_repo" &&
create_commits_in "$master_repo" A B C D E F G H I J K L M N O P Q R
'

#############################################################################
# Chart of packs and objects for this test case
#
# | T A B C D E F G H I J K L M N O P Q R
# ----+--------------------------------------
# P1 | x x x x x x x x
# P2 | x x x x x x x
# P3 | x x x x x x
# ----+--------------------------------------
# ALL | x x x x x x x x x x x x x x x
#
#############################################################################
test_expect_success 'master: no redundant for pack 1, 2, 3' '
create_pack_in "$master_repo" P1 <<-EOF &&
$T
$A
$B
$C
$D
$E
$F
$R
EOF
create_pack_in "$master_repo" P2 <<-EOF &&
$B
$C
$D
$E
$G
$H
$I
EOF
create_pack_in "$master_repo" P3 <<-EOF &&
$F
$I
$J
$K
$L
$M
EOF
(
cd "$master_repo" &&
git pack-redundant --all >out &&
test_must_be_empty out
)
'

(5)在腳本的結尾,用 test_done 方法結束測試用例。

test_done

五 Sharness 測試框架結構

Sharness 項目由 Git 項目的測試框架抽象而來,項目地址:

??https://github.com/chriscool/sharness??

Sharness 測試框架示例

  • 待測應用放在項目的根目錄。
  • 測試腳本命名為 .t,即擴展名為 .t 的腳本文件。
  • 每一個測試用例在執行時會創建一個獨立的臨時目錄,例如 trash directory.simple.t。測試用例執行成功,則該目錄會被刪除。
  • 在 sharness.d 目錄下添加自定義腳本,可以擴展 Sharness 框架。即在框架代碼加載時,自動加載該目錄下文件。

我們對 Sharness 測試框架做了一些小改動:

  • 定制版本對測試框架代碼做了進一步封裝,框架代碼放在單獨的子目錄。
  • 測試腳本的名稱恢復為和 Git 項目測試腳本類似的名稱(tNNNN-.sh), 即以字母 t 和四位數字開頭的腳本文件。

定制版 Sharness 測試框架示例

六 Sharness 測試用例格式

以如下測試腳本為例[4]:

(1)在文件頭,定義 test_description 變量,提供測試用例的簡單說明,通常使用一行文本。

#!/bin/sh      
test_description="git-repo init"

(2)包含測試框架代碼。

. ./lib/sharness.sh

(3)定義全局變量,以及定義要在測試用例中用到的函數封裝。

# Create manifest repositories  
manifest_url="file://${REPO_TEST_REPOSITORIES}/hello/manifests"

(4)用 test_expect_success 等方法撰寫測試用例。

test_expect_success "setup" ' 
# create .repo file as a barrier, not find .repo deeper
touch .repo &&
mkdir work
'

test_expect_success "git-repo init -u" '
(
cd work &&
git-repo init -u $manifest_url
)
'

test_expect_success "manifest points to default.xml" '
(
cd work &&
test -f .repo/manifest.xml &&
echo manifests/default.xml >expect &&
readlink .repo/manifest.xml >actual &&
test_cmp expect actual
)
'

(5)在腳本的結尾,用 test_done 方法結束測試用例。

test_done

七 關于 test_expect_success 方法的參數

test_expect_success 可以有兩個參數或者三個參數。

當 test_expect_success 方法后面是兩個參數時,第一個參數用于描述測試用例, 第二個參數是測試用例要執行的命令。

test_expect_success 'initial checksum' ' 
(
cd bare.git &&
git checksum --init &&
test -f info/checksum &&
test -f info/checksum.log
) &&
cat >expect <<-EOF &&
INFO[<time>]: initialize checksum
EOF
cat bare.git/info/checksum.log |
sed -e "s/\[.*\]/[<time>]/" >actual &&
test_cmp expect actual
'

當 test_expect_success 方法后面是三個參數時,第一個參數是前置條件, 第二個參數用于描述測試用例, 第三個參數是測試用例要執行的命令。

例如如下有三個參數的測試,第一個參數定義了前置條件,在 CYGWIN 等環境, 不執行測試用例。

test_expect_success !MINGW,!CYGWIN \ 
’correct handling of backslashes' '
rm -rf whitespace &&
mkdir whitespace &&
>"whitespace/trailing 1 " &&
>"whitespace/trailing 2 \\\\" &&
>"whitespace/trailing 3 \\\\" &&
>"whitespace/trailing 4 \\ " &&
>"whitespace/trailing 5 \\ \\ " &&
>"whitespace/trailing 6 \\a\\" &&
>whitespace/untracked &&
sed -e "s/Z$//" >ignore <<-\EOF &&
whitespace/trailing 1 \ Z
whitespace/trailing 2 \\\\Z
whitespace/trailing 3 \\\\ Z
whitespace/trailing 4 \\\ Z
whitespace/trailing 5 \\ \\\ Z
whitespace/trailing 6 \\a\\Z
EOF
echo whitespace/untracked >expect &&
git ls-files -o -X ignore whitespace >actual 2>err &&
test_cmp expect actual &&
test_must_be_empty err
'

八 Sharness 語法規范和技巧

使用 && 級聯各個命令,確保所有命令都全部執行成功

test_expect_success 'shared: create new objects and packs' ' 
create_commits_in "$shared_repo" X Y Z &&
create_pack_in "$shared_repo" Px1 <<-EOF &&
$X
$Y
$Z
$A
$B
$C
EOF
create_pack_in "$shared_repo" Px2 <<-EOF
$X
$Y
$Z
$D
$E
$F
EOF
'

自定義方法,也要使用 && 級聯,確保命令全部執行成功

create_pack_in () { 
repo="$1" &&
name="$2" &&
pack=$(git -C "$repo/objects/pack" pack-objects -q pack) &&
eval $name=$pack &&
eval P$pack=$name:$pack
}

涉及到目錄切換,在子 Shell 中進行,以免影響后續測試用例執行時的工作目錄

test_expect_success 'master: one of pack-2/pack-3 is redundant' ' 
create_pack_in "$master_repo" P4 <<-EOF &&
$J
$K
$L
$M
$P
EOF
create_pack_in "$master_repo" P5 <<-EOF &&
$G
$H
$N
$O
EOF
(
cd "$master_repo" &&
cat >expect <<-EOF &&
P3:$P3
EOF
git pack-redundant --all >out &&
format_packfiles <out >actual &&
test_cmp expect actual
)
'

函數命名要有意義

如下內容是 Junio 在代碼評審時,對測試用例中定義的 format_git_output 方法的評審意見。Junio 指出要在給函數命名時,要使用更有意義的名稱。

> +format_git_output () { 

Unless this helper is able to take any git output and massage,
please describe what kind of git output it is meant to handle.

Also, "format" does not tell anything to the readers why it wants to
transform its input or what its output is supposed to look like. It
does not help readers and future developers.

Heredoc 的小技巧

使用 heredoc 創建文本文件,如果其中的腳本要定義和使用變量,要對變量中的 $ 字符進行轉移。Junio 給出了一個 heredoc 語法的小技巧,可以無需對 $ 字符轉義。

> + 
> + # setup pre-receive hook
> + cat >upstream/hooks/pre-receive <<-EOF &&

Wouldn't it make it easier to read the resulting text if you quoted
the end-of-here-text marker here, i.e. "<<\-EOF"? That way, you can
lose backslash before $old, $new and $ref.

> + #!/bin/sh
> +
> + printf >&2 "# pre-receive hook\n"
> +
> + while read old new ref
> + do
> + printf >&2 "pre-receive< \$old \$new \$ref\n"
> + done
> + EOF

Shell 編程語法規范

Git 項目對于 Shell 編寫的測試用例制定了語法規范,例如:

  • 使用 tab 縮進。
  • 規定 case 語句、if 語句的縮進格式。
  • 輸入輸出重定向字符后面不要有空格。
  • 使用 $(command) 而不是 `command` 。
  • 使用 test 方法,不要使用 [ ... ] 。

完整語法規范參考[5]。

九 sharness 常見的內置函數

  • test_expect_success

開始一個測試用例。

  • test_expect_failure

標記為存在已知問題,執行失敗不報錯,執行成功則警告該 broken 的用例已經 fixed。

  • test_must_fail

后面的一條命令必須失敗。如果后面命令成功,測試失敗。

  • test_expect_code

命令以給定返回值結束。

  • test_cmp

比較兩個文件內容,相同成功,不同失敗并顯示差異。

  • test_path_is_file

參數必須是一個文件,且存在。

  • test_path_is_dir

參數必須是一個目錄,且存在。

  • test_must_be_empty

參數指向的文件內容必須為空。

  • test_seq

跨平臺的 seq,用戶生成數字序列。

  • test_pause

測試暫停,進入子 Shell。

  • test_done

測試用例結束。

十 擴展 Sharness

Sharness 提供了擴展功能。用戶在 sharness.d 目錄中添加以 .sh 結尾的腳本文件,即可對 Sharness 進行擴展。例如:

  • 在 trash directory.* 目錄下執行 git init 命令。目的是避免目錄逃逸時誤執行 git 命令影響項目本身代碼。

例如:測試腳本在工作區下創建了一個倉庫(git init my.repo),想要在該倉庫下執行 git clean,卻忘了進入到 my.repo 子目錄再執行,結果導致待測試項目中丟失文件。

  • 引入 Git 項目中的一些有用的測試方法。

如:test_tick 方法,可以設置 GIT_AUTHOR_DATE、GIT_COMMITTER_DATE 等環境變量,確保測試腳本多次運行時提交時間的一致性,進而產生一致的提交ID。

  • 引入項目需要的其他自定義方法。

例如 git-repo 項目為了避免工作區逃逸,在 trash directory.* 目錄下創建 .repo 文件。

十一 Sharness 在項目中的實戰

git-repo 是一個命令行工具,非常適合使用 sharness 測試框架編寫測試用例。參見[6]。

對于非命令行工具,或者為了測試內置函數,需要先封裝一個或多個 fake app,再調用封裝的命令行工具進行測試。例如在為 Git 項目開發 proc-receive 鉤子擴展時,先開發一個 fake app[7]。

之后再編寫測試,調用 fake app(test-tool proc-receive),幫助完成測試用例的開發。參見下列提交中的測試用例[8]。

還可以使用一些 Shell 編程技巧,在多個測試文件中復用測試用例。例如如下測試用例在測試 HTTP 協議和本地協議時,復用了同一套測試用例(t5411目錄下的測試腳本)[9]。

相關鏈接

[1]https://www.worldhello.net/2013/10/26/test-gistore-using-git-test-framework.html

[2]https://sourcegraph.com/github.com/git/git@master/-/tree/t

[3]https://github.com/git/git/blob/master/t/t5323-pack-redundant.sh

[4]https://github.com/alibaba/git-repo-go/blob/master/test/t0100-init.sh

[5]https://github.com/git/git/blob/master/Documentation/CodingGuidelines

[6]https://github.com/alibaba/git-repo-go

[7]https://github.com/jiangxin/git/blob/jx/proc-receive-hook/t/helper/test-proc-receive.c

[8]https://github.com/jiangxin/git/commit/9654f5eda1153634ab09ca5c6e490bcabdd57e61

[9]https://github.com/jiangxin/git/blob/jx/proc-receive-hook/t/t5411-proc-receive-hook.sh還分享了 Sharness 的擴展功能和項目實戰。

【本文為51CTO專欄作者“阿里巴巴官方技術”原創稿件,轉載請聯系原作者】

??戳這里,看該作者更多好文??

 

責任編輯:武曉燕 來源: 51CTO專欄
相關推薦

2020-11-04 16:34:45

單元測試技術

2021-03-04 15:43:29

前端測試工具開發

2011-05-16 15:18:18

測試用例

2011-06-08 17:23:12

測試用例

2022-05-10 14:54:13

驗收標準測試用例

2021-12-22 10:19:47

鴻蒙HarmonyOS應用

2011-05-16 15:09:20

測試用例

2011-04-18 10:46:39

接口測試

2020-07-10 12:06:28

WebpackBundleless瀏覽器

2022-01-19 17:48:57

測試用例開發

2011-05-16 14:54:12

測試用例

2011-07-04 18:06:52

測試用例

2023-06-09 15:24:50

UiTest接口鴻蒙

2011-12-23 17:03:29

性能測試用例設計

2022-06-13 09:00:00

Selenium測試Web

2011-09-01 10:05:24

PhoneGap應用程序測試

2020-12-02 08:31:47

Elasticsear

2022-06-17 11:10:43

PandasPolarsPython

2025-05-27 01:45:00

DeepSeekPython測試

2011-06-03 16:58:03

測試用例
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩免费视频一区二区 | 国产在线精品免费 | 免费久| 国产成人一区 | 欧美成视频| av网站免费在线观看 | 日韩在线视频免费观看 | 日本特黄a级高清免费大片 国产精品久久性 | 国产成视频在线观看 | 国产福利资源在线 | 精品免费国产视频 | 日韩一区二区三区精品 | 四虎在线观看 | 成人精品一区二区 | 欧美性一区二区三区 | 天天插天天干 | 亚洲国产高清在线 | 国产91久久精品一区二区 | 在线视频日韩 | 日日干夜夜操 | 免费在线一区二区三区 | 国产精品久久久久久久久久免费看 | 夜夜爽99久久国产综合精品女不卡 | 成年人精品视频在线观看 | 91精品国产高清一区二区三区 | 天天久久 | 精品国产精品三级精品av网址 | av在线免费观看网站 | 欧美 视频 | 国产精品爱久久久久久久 | 国产精品xxxx | a级性视频| 精品无码三级在线观看视频 | 久久国产欧美日韩精品 | 黄网站免费入口 | 久久久久久免费毛片精品 | 国产成人综合在线 | 国产美女自拍视频 | 亚洲综合五月天婷婷 | 久久久久久av | 国产精品美女视频 |