当前位置: 首页 > 科技观察

写测试用例难?试用Sharness

时间:2023-03-13 20:28:44 科技观察

Sharness是一个用于在shell脚本中编写测试用例的测试框架。本文将详细介绍Sharness的结构和测试用例的编写格式,以及语法规范和技巧,教你如何使用Sharness编写测试用例。同时,你参与了Git项目的测试用例开发,对其测试框架的简洁高效印象深刻。尝试将Git测试用例用于其他项目:《复用 git.git 测试框架》[1]。然而,从Git项目中剥离测试用例框架是相当费力的。一次偶然的机会,发现有人(ChristianCouder:Gitlab工程师,Git项目领导委员会成员之一)已经将Git测试用例框架分离出来,成为一个独立的开源项目Sharness。有了Sharness,编写测试用例不再是一件苦差事。1.什么是锐度?Sharness是一个使用Shell脚本编写测试用例的测试框架。测试用例可以在Linux和macOS平台上运行。测试输出符合TAP(testanythingprotocol),因此可以使用sharness自带的工具或者prove等兼容TAP的测试工具运行。是Junio在2005年为Git项目开发的测试框架,由ChristianCouder(chriscool)从Git中剥离出来作为一个独立的测试框架。地址:https://github.com/chriscool/sharnessSharness测试框架的两大优势简洁如果你想在测试用例中创建/初始化一个文件(内容是“Hello,world.”),看看它是多么简单implementsharness:cat>expect<<-EOFHello,world.EOF如果你想将应用程序(hello-world)的输出与预期的expect文件进行比较,如果它们相同,则测试用例通过;如果它们不同,则显示差异。测试用例写法如下:test_expect_success"appoutputtest"'cat>expect<<-EOF&&Hello,world.EOFhello-world>actual&&test_cmpexpectactual'调试方便每个测试用例脚本可以单独执行。可以使用-v参数显示详细输出。使用-d参数在运行结束后保留??用例的临时目录。可以在要调试的测试用例后面加上test_pause语句,例如:test_expect_success"name"''test_pausetest_done然后使用-v参数运行脚本,会在test_pause语句处中断,输入包含sharness环境变量的子shell,目录切换到测试用例的单独工作区。调试完毕,退出Shell并返回。三个Git项目的测试框架结构Sharness均来源于Git项目的测试用例框架。我们先来看一下Git项目测试框架的结构。Git项目测试相关文件待测试的应用放在项目的根目录下。例如Git项目的被测应用:git和git-receive-pack等。测试框架修改PATH环境变量,使得测试用例调用被测应用(如git命令)时,优先使用项目根目录下的被测应用。测试脚本命名为tNNNN-.sh,即以字母t和四位数字开头的脚本文件。每个测试用例在执行过程中都会创建一个独立的临时目录,比如trashdirectory.t5323-pack-redundant。如果测试用例执行成功,该目录将被删除。相关代码见[2]。四种Git测试脚本格式以下面的测试脚本为例[3]:(1)在文件头中定义test_description变量,提供对测试用例的简单描述,通常使用一行文本。这个测试用例比较复杂,用了多行文字来描述。#!/bin/sh##Copyright(c)2018JiangXin#test_description='测试gitpack-redundant为了测试git-pack-redundant,我们将在存储库`master.git`中创建一些对象和包。包(P1-P8)和对象(T,A-R)之间的关系如下图所示。对象sofapack将用letterx标记,而ex对象将标记为redundant和冗余包本身将标有星号。|TABCDEFGHIJKLMNOPQR----+----------------------------------------P1|xxxxxxxxP2*|!!!!!P3|xxxxxxP4*|!!!!!P5|xxxxP6*|!!!P7|xxP8*|!----+------------------------------------ALL|xxxxxxxxxxxxxxxxxxxxxxAnotherrepository`shared.git`hasuniqueobjects(X-Z),whileotherobjects(markedwithletters)通过alt-odb(of`master.git`)共享。包和对象之间的关系如下:|TABCDEFGHIJKLMNOPQRXYZ----+----------------------------------------------Px1|sssxxxPx2|sssxxx'(2)包含测试框架代码。../test-lib.sh(3)定义全局变量,定义测试用例使用的函数包。master_repo=master.gitshared_repo=shared.git#Createcommitsinandassigneachcommit'soidtoshellvariables#giveninthearguments(A,B,andC).E.g.:##create_commits_inABC##NOTE:Avoidcallingthisfunctionfromasubshel??lsincevariable#assignmentswilldisappearwhensubshel??lexits.create_commits_in(){回购="$1"&&if!parent=$(git-C"$repo"rev-parseHEAD^{}2>/dev/null)then......(4)用test_expect_success等方法测写测试用例。test_expect_success'setupmasterrepo''gitinit--bare"$master_repo"&&create_commits_in"$master_repo"ABCDEFGHIJKLMNOPQR'###############################################################################这个测试用例的包和对象图表##|TABCDEFGHIJKLMNOPQR#----+------------------------------------#P1|xxxxxxxx#P2|xxxxxxx#P3|xxxxxx#----+---------------------------------------#ALL|xxxxxxxxxxxxxxx#################################################################################test_expect_success'master:noredundantforpack1,2,3''create_pack_in"$master_repo"P1<<-EOF&&$T$A$B$C$D$E$F$REOFcreate_pack_in"$master_repo"P2<<-EOF&&$B$C$D$E$G$H$IEOFcreate_pack_in"$master_repo"P3<<-EOF&&$F$I$J$K$L$MEOF(cd"$master_repo"&&gitpack-redundant--all>out&&test_must_be_emptyout)'(5)test_done方法完成测试示例。test_done5Sharness测试框架结构Sharness项目是从Git项目的测试框架中抽象出来的。项目地址:https://github.com/chriscool/sharnessSharness测试框架示例待测应用放在项目根目录下。测试脚本以.t命名,即以.t为扩展名的脚本文件。每个测试用例在执行时都会创建一个独立的临时目录,比如trashdirectory.simple.t。如果测试用例执行成功,该目录将被删除。您可以通过在sharness.d目录下添加自定义脚本来扩展Sharness框架。即框架代码加载时,会自动加载该目录下的文件。我们对Sharness测试框架做了一些小改动:定制版进一步封装了测试框架代码,框架代码放在了单独的子目录下。测试脚本的名称恢复为类似于Git项目测试脚本(tNNNN-.sh)的名称,即以字母t开头和一个四位数字的脚本文件。定制版Sharness测试框架示例6Sharness测试用例格式以下面的测试脚本为例[4]:(1)在文件头,定义test_description变量,提供对测试用例的简单描述,通常使用一行文字。#!/bin/shtest_description="git-repoint"(2)包含测试框架代码。../lib/sharness.sh(3)定义全局变量,定义测试用例使用的函数包。#Createmanifestrepositoriesmanifest_url="file://${REPO_TEST_REPOSITORIES}/hello/manifests"(4)用test_expect_success等方法编写测试用例。test_expect_success"setup"'#create.repofileasabarrier,notfind.repodeepertouch.repo&&mkdirwork'test_expect_success"git-repoinit-u"'(cdwork&&git-repoinit-u$manifest_url)'test_expect_success"manifestpointstodefault.xml"'(cdwork&&test-f.repo/manifest.xml&&echomanifests/default.xml>expect&&readlink.repo/manifest.xml>actual&&test_cmpexpectactual)'(5)在脚本最后,使用test_done方法结束测试用例。test_done七、关于test_expect_success方法的参数test_expect_success可以有两个参数也可以有三个参数。当test_expect_success方法后面有两个参数时,第一个参数用来描述测试用例,第二个参数是测试用例要执行的命令。test_expect_success'初始校验和''(cdbare.git&&gitchecksum--init&&test-finfo/checksum&&test-finfo/checksum.log)&&cat>expect<<-EOF&&INFO[