自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

測(cè)試用例難寫?來(lái)試試 Sharness

開(kāi)發(fā) 開(kāi)發(fā)工具
Sharness 是一個(gè)用 Shell 腳本來(lái)編寫測(cè)試用例的測(cè)試框架。本文將詳細(xì)介紹 Sharness 的結(jié)構(gòu)及測(cè)試用例的編寫格式,以及語(yǔ)法規(guī)范和技巧,教大家如何使用 Sharness 編寫測(cè)試用例,同時(shí)參與過(guò) Git 項(xiàng)目的測(cè)試用例開(kāi)發(fā),為其測(cè)試框架的簡(jiǎn)潔、高效而折服。

Sharness 是一個(gè)用 Shell 腳本來(lái)編寫測(cè)試用例的測(cè)試框架。本文將詳細(xì)介紹 Sharness 的結(jié)構(gòu)及測(cè)試用例的編寫格式,以及語(yǔ)法規(guī)范和技巧,教大家如何使用 Sharness 編寫測(cè)試用例,同時(shí)參與過(guò) Git 項(xiàng)目的測(cè)試用例開(kāi)發(fā),為其測(cè)試框架的簡(jiǎn)潔、高效而折服。曾經(jīng)嘗試將 Git 測(cè)試用例用于其他項(xiàng)目:《復(fù)用 git.git 測(cè)試框架》[1]。不過(guò)從 Git 項(xiàng)目中剝離測(cè)試用例框架還是挺費(fèi)事的。

一次偶然的機(jī)會(huì)發(fā)現(xiàn)已經(jīng)有人(Christian Couder:Gitlab 工程師,Git項(xiàng)目的領(lǐng)導(dǎo)委員會(huì)成員之一)已經(jīng)將 Git 的測(cè)試用例框架剝離出來(lái), 成為獨(dú)立的開(kāi)源項(xiàng)目 Sharness。

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

一 Sharness 是什么?

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

二 Sharness 測(cè)試框架的優(yōu)點(diǎn)

簡(jiǎn)潔

如果要在測(cè)試用例中創(chuàng)建/初始化一個(gè)文件(內(nèi)容為 “Hello, world.”), 看看 sharness 實(shí)現(xiàn)起來(lái)有多么簡(jiǎn)單:

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

如果要對(duì)某應(yīng)用(hello-world)的輸出和預(yù)期的 expect 文件進(jìn)行比較, 相同則測(cè)試用例通過(guò),不同則展示差異。測(cè)試用例編寫如下:

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

調(diào)試方便

每個(gè)測(cè)試用例腳本可以單獨(dú)執(zhí)行。使用 -v 參數(shù),可以顯示詳細(xì)輸出。使用 -d 參數(shù),運(yùn)行結(jié)束后保留用例的臨時(shí)目錄。

可以在要調(diào)試的test case后面增加 test_pause 語(yǔ)句,例如:

test_expect_success “name” ‘ 
<Script…>


test_pause
test_done

然后使用 -v 參數(shù)運(yùn)行該腳本,會(huì)在 test_pause 語(yǔ)句處中斷,進(jìn)入一個(gè)包含 sharness 環(huán)境變量的子 Shell 中,目錄會(huì)切換到測(cè)試用例單獨(dú)的工作區(qū)。調(diào)試完畢退出 Shell 即返回。

三 Git 項(xiàng)目的測(cè)試框架結(jié)構(gòu)

Sharness 源自于 Git 項(xiàng)目的測(cè)試用例框架。我們先來(lái)看看 Git 項(xiàng)目測(cè)試框架的結(jié)構(gòu)。

Git 項(xiàng)目測(cè)試相關(guān)文件

  • 待測(cè)應(yīng)用放在項(xiàng)目的根目錄。例如 Git 項(xiàng)目的待測(cè)應(yīng)用: git 和 git-receive-pack 等。
  • 測(cè)試框架修改 PATH 環(huán)境變量,使得測(cè)試用例在調(diào)用待測(cè)應(yīng)用(如 git 命令)的時(shí)候,優(yōu)先使用項(xiàng)目根目錄下的待測(cè)應(yīng)用。
  • 測(cè)試腳本命名為 tNNNN-.sh,即以字母 t 和四位數(shù)字開(kāi)頭的腳本文件。
  • 每一個(gè)測(cè)試用例在執(zhí)行時(shí)會(huì)創(chuàng)建一個(gè)獨(dú)立的臨時(shí)目錄,例如 trash directory.t5323-pack-redundant。測(cè)試用例執(zhí)行成功,則該目錄會(huì)被刪除。

相關(guān)代碼參見(jiàn)[2]。

四 Git 測(cè)試腳本的格式

以如下測(cè)試腳本為例[3]:

(1)在文件頭,定義 test_description 變量,提供測(cè)試用例的簡(jiǎn)單說(shuō)明,通常使用一行文本。本測(cè)試用例較為復(fù)雜,使用了多行文本進(jìn)行描述。

#!/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)包含測(cè)試框架代碼。

. ./test-lib.sh

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

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 等方法撰寫測(cè)試用例。

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)在腳本的結(jié)尾,用 test_done 方法結(jié)束測(cè)試用例。

test_done

五 Sharness 測(cè)試框架結(jié)構(gòu)

Sharness 項(xiàng)目由 Git 項(xiàng)目的測(cè)試框架抽象而來(lái),項(xiàng)目地址:

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

Sharness 測(cè)試框架示例

  • 待測(cè)應(yīng)用放在項(xiàng)目的根目錄。
  • 測(cè)試腳本命名為 .t,即擴(kuò)展名為 .t 的腳本文件。
  • 每一個(gè)測(cè)試用例在執(zhí)行時(shí)會(huì)創(chuàng)建一個(gè)獨(dú)立的臨時(shí)目錄,例如 trash directory.simple.t。測(cè)試用例執(zhí)行成功,則該目錄會(huì)被刪除。
  • 在 sharness.d 目錄下添加自定義腳本,可以擴(kuò)展 Sharness 框架。即在框架代碼加載時(shí),自動(dòng)加載該目錄下文件。

我們對(duì) Sharness 測(cè)試框架做了一些小改動(dòng):

  • 定制版本對(duì)測(cè)試框架代碼做了進(jìn)一步封裝,框架代碼放在單獨(dú)的子目錄。
  • 測(cè)試腳本的名稱恢復(fù)為和 Git 項(xiàng)目測(cè)試腳本類似的名稱(tNNNN-.sh), 即以字母 t 和四位數(shù)字開(kāi)頭的腳本文件。

定制版 Sharness 測(cè)試框架示例

六 Sharness 測(cè)試用例格式

以如下測(cè)試腳本為例[4]:

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

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

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

. ./lib/sharness.sh

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

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

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

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)在腳本的結(jié)尾,用 test_done 方法結(jié)束測(cè)試用例。

test_done

七 關(guān)于 test_expect_success 方法的參數(shù)

test_expect_success 可以有兩個(gè)參數(shù)或者三個(gè)參數(shù)。

當(dāng) test_expect_success 方法后面是兩個(gè)參數(shù)時(shí),第一個(gè)參數(shù)用于描述測(cè)試用例, 第二個(gè)參數(shù)是測(cè)試用例要執(zhí)行的命令。

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
'

當(dāng) test_expect_success 方法后面是三個(gè)參數(shù)時(shí),第一個(gè)參數(shù)是前置條件, 第二個(gè)參數(shù)用于描述測(cè)試用例, 第三個(gè)參數(shù)是測(cè)試用例要執(zhí)行的命令。

例如如下有三個(gè)參數(shù)的測(cè)試,第一個(gè)參數(shù)定義了前置條件,在 CYGWIN 等環(huán)境, 不執(zhí)行測(cè)試用例。

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 語(yǔ)法規(guī)范和技巧

使用 && 級(jí)聯(lián)各個(gè)命令,確保所有命令都全部執(zhí)行成功

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
'

自定義方法,也要使用 && 級(jí)聯(lián),確保命令全部執(zhí)行成功

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 中進(jìn)行,以免影響后續(xù)測(cè)試用例執(zhí)行時(shí)的工作目錄

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
)
'

函數(shù)命名要有意義

如下內(nèi)容是 Junio 在代碼評(píng)審時(shí),對(duì)測(cè)試用例中定義的 format_git_output 方法的評(píng)審意見(jiàn)。Junio 指出要在給函數(shù)命名時(shí),要使用更有意義的名稱。

> +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 創(chuàng)建文本文件,如果其中的腳本要定義和使用變量,要對(duì)變量中的 $ 字符進(jìn)行轉(zhuǎn)移。Junio 給出了一個(gè) heredoc 語(yǔ)法的小技巧,可以無(wú)需對(duì) $ 字符轉(zhuǎn)義。

> + 
> + # 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 編程語(yǔ)法規(guī)范

Git 項(xiàng)目對(duì)于 Shell 編寫的測(cè)試用例制定了語(yǔ)法規(guī)范,例如:

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

完整語(yǔ)法規(guī)范參考[5]。

九 sharness 常見(jiàn)的內(nèi)置函數(shù)

  • test_expect_success

開(kāi)始一個(gè)測(cè)試用例。

  • test_expect_failure

標(biāo)記為存在已知問(wèn)題,執(zhí)行失敗不報(bào)錯(cuò),執(zhí)行成功則警告該 broken 的用例已經(jīng) fixed。

  • test_must_fail

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

  • test_expect_code

命令以給定返回值結(jié)束。

  • test_cmp

比較兩個(gè)文件內(nèi)容,相同成功,不同失敗并顯示差異。

  • test_path_is_file

參數(shù)必須是一個(gè)文件,且存在。

  • test_path_is_dir

參數(shù)必須是一個(gè)目錄,且存在。

  • test_must_be_empty

參數(shù)指向的文件內(nèi)容必須為空。

  • test_seq

跨平臺(tái)的 seq,用戶生成數(shù)字序列。

  • test_pause

測(cè)試暫停,進(jìn)入子 Shell。

  • test_done

測(cè)試用例結(jié)束。

十 擴(kuò)展 Sharness

Sharness 提供了擴(kuò)展功能。用戶在 sharness.d 目錄中添加以 .sh 結(jié)尾的腳本文件,即可對(duì) Sharness 進(jìn)行擴(kuò)展。例如:

  • 在 trash directory.* 目錄下執(zhí)行 git init 命令。目的是避免目錄逃逸時(shí)誤執(zhí)行 git 命令影響項(xiàng)目本身代碼。

例如:測(cè)試腳本在工作區(qū)下創(chuàng)建了一個(gè)倉(cāng)庫(kù)(git init my.repo),想要在該倉(cāng)庫(kù)下執(zhí)行 git clean,卻忘了進(jìn)入到 my.repo 子目錄再執(zhí)行,結(jié)果導(dǎo)致待測(cè)試項(xiàng)目中丟失文件。

  • 引入 Git 項(xiàng)目中的一些有用的測(cè)試方法。

如:test_tick 方法,可以設(shè)置 GIT_AUTHOR_DATE、GIT_COMMITTER_DATE 等環(huán)境變量,確保測(cè)試腳本多次運(yùn)行時(shí)提交時(shí)間的一致性,進(jìn)而產(chǎn)生一致的提交ID。

  • 引入項(xiàng)目需要的其他自定義方法。

例如 git-repo 項(xiàng)目為了避免工作區(qū)逃逸,在 trash directory.* 目錄下創(chuàng)建 .repo 文件。

十一 Sharness 在項(xiàng)目中的實(shí)戰(zhàn)

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

對(duì)于非命令行工具,或者為了測(cè)試內(nèi)置函數(shù),需要先封裝一個(gè)或多個(gè) fake app,再調(diào)用封裝的命令行工具進(jìn)行測(cè)試。例如在為 Git 項(xiàng)目開(kāi)發(fā) proc-receive 鉤子擴(kuò)展時(shí),先開(kāi)發(fā)一個(gè) fake app[7]。

之后再編寫測(cè)試,調(diào)用 fake app(test-tool proc-receive),幫助完成測(cè)試用例的開(kāi)發(fā)。參見(jiàn)下列提交中的測(cè)試用例[8]。

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

相關(guān)鏈接

[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 的擴(kuò)展功能和項(xiàng)目實(shí)戰(zhàn)。

【本文為51CTO專欄作者“阿里巴巴官方技術(shù)”原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)聯(lián)系原作者】

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

 

責(zé)任編輯:武曉燕 來(lái)源: 51CTO專欄
相關(guān)推薦

2020-11-04 16:34:45

單元測(cè)試技術(shù)

2021-03-04 15:43:29

前端測(cè)試工具開(kāi)發(fā)

2011-06-08 17:23:12

測(cè)試用例

2011-05-16 15:18:18

測(cè)試用例

2022-05-10 14:54:13

驗(yàn)收標(biāo)準(zhǔn)測(cè)試用例

2021-12-22 10:19:47

鴻蒙HarmonyOS應(yīng)用

2011-05-16 15:09:20

測(cè)試用例

2011-04-18 10:46:39

接口測(cè)試

2020-07-10 12:06:28

WebpackBundleless瀏覽器

2011-05-16 14:54:12

測(cè)試用例

2022-01-19 17:48:57

測(cè)試用例開(kāi)發(fā)

2011-07-04 18:06:52

測(cè)試用例

2011-12-23 17:03:29

性能測(cè)試用例設(shè)計(jì)

2023-06-09 15:24:50

UiTest接口鴻蒙

2022-06-13 09:00:00

Selenium測(cè)試Web

2011-09-01 10:05:24

PhoneGap應(yīng)用程序測(cè)試

2020-12-02 08:31:47

Elasticsear

2022-06-17 11:10:43

PandasPolarsPython

2024-09-29 15:26:53

MySQLPython

2011-11-02 09:54:37

測(cè)試
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)