# -------------------------------------------- # Main routine for performing the test bucket # -------------------------------------------- CALLER=`basename $0` # The Caller name SILENT="no" # User wants prompts let "errorCounter = 0" # ---------------------------------- # Handle keyword parameters (flags). # ---------------------------------- # For more sophisticated usage of getopt in Linux, # see the samples file: /usr/lib/getopt/parse.bash TEMP=`getopt hs $*` if [ $? != 0 ] then echo "$CALLER: Unknown flag(s)" usage fi # Note quotes around `$TEMP': they are essential! eval(231, 243, 237); padding: 0px 3px; border-radius: 4px; overflow-wrap: break-word; text-indent: 0px;">CALLER=`basename $0` 可以得到正在运行的脚本名称。这样的话,无须在脚本中硬编码脚本名称。因此当复制脚本时,采用新派生的脚本可以减少工作量。 调用脚本时,语句TEMP=`getopt hs $*` 用于得到输入变量(例如 -h 代表帮助,-s 代表安静模式)。语句[ -z "$X" ] 和echo "The environment variable X is not set." 以及usage 都是用于检测字符串是否为空 (-z),如果为空,随后就执行 echo 语句以显示未设置字符串并调用下面要讨论的 "usage" 函数。若脚本未使用标志,可以使用变量 "$#",它可以返回正在传递到脚本的变量数量。7. 尝试提供“usage”反馈 脚本中使用 "usage" 语句是个好主意,它用来说明如何使用脚本。 # ---------------------------- # Subroutine to echo the usage # ---------------------------- usage() { echo "USAGE: $CALLER [-h] [-s]" echo "WHERE: -h = help " echo " -s = silent (no prompts)" echo "PREREQUISITES:" echo "* The environment variable TEST_VAR must be set," echo "* such as: " echo " export TEST_VAR=1" echo "$CALLER: exiting now with rc=1." exit 1 } |
调用脚本时,使用“-h”标志可以调用 "usage" 语句,如下所示: ./test-bucket-1 -h 8. 尝试使用“安静”的运行模式 您或许想让脚本有两种运行模式: - 在 "verbose" 模式(您也许想将此作为缺省值)中提示用户输入值,或者只需按下 Enter 继续运行。
- 在 "silent" 模式中将不提示用户输入数据。
下列摘录说明了在安静模式下运用所调用标志 "-s" 来运行脚本: # ------------------------------------------------- # Everything seems OK, prompt for confirmation # ------------------------------------------------- if [ "$SILENT" = "yes" ] then RESPONSE="y" else echo "The $CALLER will be performed." echo "Do you wish to proceed [y or n]? " read RESPONSE # Wait for response [ -z "$RESPONSE" ] && RESPONSE="n" fi case "$RESPONSE" in [yY]|[yY][eE]|[yY][eE][sS]) ;; *) echo "$CALLER terminated with rc=1." exit 1 ;; esac |
9. 当出现错误时,提供一个函数终止脚本 遇到严重错误时,提供一个中心函数以终止运行的脚本不失为一个好主意。此函数还可提供附加的说明,用于指导在此情况下应做些什么: # ---------------------------------- # Subroutine to terminate abnormally # ---------------------------------- terminate() { echo "The execution of $CALLER was not successful." echo "$CALLER terminated, exiting now with rc=1." dateTest=`date` echo "End of testing at: $dateTest" echo "" exit 1 } |
10. 如有可能,提供可以执行简单任务的函数 例如,不使用许多很长的行命令,如: # -------------------------------------------------- echo "" echo "Creating Access lists..." # -------------------------------------------------- Access -create -component Development -login ted -authority plead -verbose if [ $? -ne 0 ] then echo "ERROR found in Access -create -component Development -login ted -authority plead" let "errorCounter = errorCounter + 1" fi Access -create -component Development -login pat -authority general -verbose if [ $? -ne 0 ] then echo "ERROR found in Access -create -component Development -login pat -authority general" let "errorCounter = errorCounter + 1" fi Access -create -component Development -login jim -authority general -verbose if [ $? -ne 0 ] then echo "ERROR found in Access -create -component Development -login jim -authority general" let "errorCounter = errorCounter + 1" fi |
……而是创建一个如下所示的函数,此函数也可以处理返回码,如果有必要,还可以增加错误计数器: CreateAccess() { Access -create -component $1 -login $2 -authority $3 -verbose if [ $? -ne 0 ] then echo "ERROR found in Access -create -component $1 -login $2 -authority $3" let "errorCounter = errorCounter + 1" fi } |
……然后,以易读和易扩展的方式调用此函数: # ------------------------------------------- echo "" echo "Creating Access lists..." # ------------------------------------------- CreateAccess Development ted projectlead CreateAccess Development pat general CreateAccess Development jim general |
11. 当显示正在生成的输出时,捕获每个脚本的输出 如果脚本不能自动地将输出发送到文件的话,可以利用 Bash shell 的一些函数来捕获所执行脚本的输出,如: ./test-bucket-1 -s 2>&1 | tee test-bucket-1.out |
让我们来分析上面的命令: - "2>&1" 命令:使用 "2>&1" 将标准错误重定向到标准输出。字符串 "2>&1" 表明任何错误都应送到标准输出,即 UNIX/Linux 下 2 的文件标识代表标准错误,而 1 的文件标识代表标准输出。如果不用此字符串,那么所捕捉到的仅仅是正确的信息,错误信息会被忽略。
- 管道 "|" 和 "tee" 命令:UNIX/Linux 进程和简单的管道概念很相似。既然这样,可以做一个管道将期望脚本的输出作为管道的输入。下一个要决定的是如何处理管道所输出的内容。在这种情况下,我们会将它捕获到输出文件中,在此示例中将之称为 "test-bucket-1.out"。
但是,除了要捕获到输出结果外,我们还想监视脚本运行时产生的输出。为达到此目的,我们连接允许两件事同时进行的 "tee" (T- 形管道):将输出结果放在文件中同时将输出结果显示在屏幕上。其管道类似于:
process --> T ---> output file | V screen |
如果 只 想捕获输出结果而不想在屏幕上看到输出结果,那可以忽略多余的管道: ./test-bucket-1 -s 2>&1 > test-bucket-1.out 假若这样,相类似的管道如下: 12. 在每个脚本内,捕获每个行命令所返回码 决定功能测试成功还是失败的一种方法是计算已失败行命令的数量,即返回码不是 0。变量 "$?" 提供最近所调用命令的返回码;在下面的示例中,它提供了执行 "ls" 命令的返回码。 # ------------------------------------------- # The commands are called in a subroutine # so that return code can be # checked for possible errors. # ------------------------------------------- ListFile() { echo "ls -al $1" ls -al $1 if [ $? -ne 0 ] then echo "ERROR found in: ls -al $1" let "errorCounter = errorCounter + 1" fi } |
13. 记录失败事务的次数 在功能测试中决定其成功或失败的一个方法是计算返回值不是 0 的行命令数量。但是,从我个人的经验而言,我习惯于在我的 Bash shell 脚本中仅使用字符串而不是整数。在我所参考的手册中没有清楚地说明如何使用整数,这就是我为什么想在此就关于如何使用整数和计算错误(行命令失败)数量的方面多展开讲的原因: 首先,需要按如下方式对计数器变量进行初始化:
然后,发出行命令并使用 $? 变量捕获返回码。如果返回码不是 0,那么计数器增加 1(见蓝色粗体语句): ListFile() { echo "ls -al $1" ls -al $1 if [ $? -ne 0 ] then echo "ERROR found in: ls -al $1" let "errorCounter = errorCounter + 1" fi } |
顺便说一下,与其它变量一样,可以使用 "echo" 显示整数变量。 14. 在输出文件中,为了容易标识,突出显示错误消息 当遇到错误(或失败的事务)时,除了错误计数器的数量会增加外,最好标识出此处有错。较理想的做法是,字符串有一个如 ERROR 或与之相似的子串(见蓝色粗体的语句),这个子串允许测试者很快地在输出文件中查找到错误。此输出文件可能很大,而且它对于迅速找到错误非常重要。 ListFile() { echo "ls -al $1" ls -al $1 if [ $? -ne 0 ] then echo "ERROR found in: ls -al $1" let "errorCounter = errorCounter + 1" fi } |
15. 如有可能,“实时”生成文件 在某些情况下,有必要处理应用程序使用的文件。可以使用现有文件,也可以在脚本中添加语句来创建文件。如果要使用的文件很长,那最好将其作为独立的实体。如果文件很小而且内容简单或不相关(重要的一点是文本文件而不考虑它的内容),那就可以决定“实时”创建这些临时文件。 下面几行代码显示如何“实时”创建临时文件: cd $HOME/fvt echo "Creating file softtar.c" echo "Subject: This is softtar.c" > softtar.c echo "This is line 2 of the file" >> softtar.c |
第一个 echo 语句使用单个的 > 强行创建新文件。第二个 echo 语句使用两个 >> 将数据附加到现有文件的后面。顺便说一下,如果该文件不存在,那么会创建一个文件。 16. 在执行脚本的过程中提供反馈 最好在脚本中包含 echo 语句以表明它执行的逻辑进展状况。可以添加一些能迅速表明输出目的的语句。 如果脚本要花费一些时间执行,那或许应在执行脚本的开始和结束的地方打印时间。这样可以计算出所花费的时间。 在脚本样本中,一些提供进展说明的 echo 语句如下所示: # -------------------------------------------- echo "Subject: Product X, FVT testing" dateTest=`date` echo "Begin testing at: $dateTest" echo "" echo "Testcase: $CALLER" echo "" # -------------------------------------------- # -------------------------------------------- echo "" echo "Listing files..." # -------------------------------------------- # The following file should be listed: ListFile $HOME/.profile ... # -------------------------------------------- echo "" echo "Creating file 1" # --------------------------------------------
|
17. 提供脚本执行的摘要 如果正在计算错误或失败事务的次数,那最好表明是否有错误。此方法使得测试者在看到输出文件的最后能迅速地辨认出是否存在错误。 在下面的脚本示例中,代码语句提供了上述脚本的执行摘要: # -------------- # Exit # -------------- if [ $errorCounter -ne 0 ] then echo "" echo "*** $errorCounter ERRORS found during ***" echo "*** the execution of this test case. ***" terminate else echo "" echo "*** Yeah! No errors were found during ***" echo "*** the execution of this test case. Yeah! ***" fi echo "" echo "$CALLER complete." echo "" dateTest=`date` echo "End of testing at: $dateTest" echo "" exit 0 # end of file |
18. 提供一个容易解释的输出文件 在脚本生成的实际输出中提供一些关键信息是非常有用的。那样,测试者就可以很容易地确定正在查看的文件是否与自己所做的相关以及它是否是当前产生的。附加的时间戳记对于是否是当前状态是很重要的。摘要报告对于确定是否有错误也是很有帮助的;如果有错误,那么测试者就必须搜索指定的关键字,例如 ERROR,并确认出个别失败的事务。 以下是一段输出文件样本的片段: Subject: CMVC 2.3.1, FVT testing, Common, Part 1 Begin testing at: Tue Apr 18 12:50:55 EDT 2000 Database: DB2 Family: cmpc3db2 Testcase: fvt-common-1 Creating Users... User pat was created successfully. ... Well done! No errors were found during the execution of this test case :) fvt-common-1 complete. End of testing at: Tue Apr 18 12:56:33 EDT 2000 |
当遇到错误时输出文件最后部分的示例如下所示: ERROR found in Report -view DefectView *** 1 ERRORS found during the execution of this test case. *** The populate action for the CMVC family was not successful. Recreating the family may be necessary before running fvt-client-3 again, that is, you must use 'rmdb', 'rmfamily', 'mkfamily' and 'mkdb -d', then issue: fvt-common-1 and optionally, fvt-server-2. fvt-client-3 terminated, exiting now with rc=1. End of testing at: Wed Jan 24 17:06:06 EST 2001 |
19. 如有可能,提供清除脚本及返回基准线的方法 测试脚本可以生成临时文件;假若这样,最好能让脚本删除所有临时文件。这就会避免由于测试者也许没有删除所有临时文件而引起的错误,更糟糕的是将所需要的文件当作临时文件而删除了。 运行功能测试的 Bash shell 脚本 本节描述如何运用 Bash shell 脚本进行功能测试。假设您已经执行了在前面部分中所述步骤。 设置必要的环境变量 根据需要在 .profile 中或手工指定下列环境变量。该变量用于说明在脚本中如何处理,所需环境变量的验证必须在脚本执行前定义。
将 Bash shell 脚本复制到正确的目录下 Bash shell 脚本和相关文件需要复制到要进行功能测试的用户标识的目录结构下。 - 登录进某个帐户。您应该在主目录下。假设它是 /home/tester。
- 为测试案例创建目录:
mkdir fvt - 复制 Bash shell 脚本和相关文件。获取压缩文件(请参阅 参考资料 )并将其放在 $HOME 下。然后将其按下列方式解压:
unzip trfvtbash.zip - 为了执行这个文件,更改文件的许可权:
chmod u+x * - 更改名称以除去文件的后缀:
mv test-bucket-1.bash test-bucket-1
运行脚本 执行下列步骤以运行脚本: - 以测试者的用户标识登录
- 更改目录至所复制脚本的位置:
cd $HOME/fvt - 从 $HOME/fvt 运行脚本:
./test-bucket-1 -s 2>&1 | tee test-bucket-1.out - 看一下输出文件 "test-bucket-1.out" 的尾部并查看摘要报告的结论。
原文: Function testing is the phase during a development cycle in which the software application is tested to ensure that the functionality is working as desired and that any errors in the code are properly handled. It is usually done after the unit testing of individual modules, and before a more thorough system test of the entire product under load/stress conditions. There are many testing tools in the marketplace that offer a lot of functionalityto help with the testing efforts. However, they need to be obtained, installed, and configured, which could take up valuable time and effort. Bash can help to speed things along. The advantages of using Bash shell scripts for function testing are: - The Bash shell is already installed and configured in yourLinux system. You do not have to spend time in getting it ready.
- You can create and modify the Bash shell scripts using text editors already providedby Linux, such as vi. You do not need to acquire specialized toolsto create the test cases.
- If you already know how to develop Bourne or Korn shell scripts, thenyou already know enough tostart working with Bash shell scripts. Your learning curve isgreatly diminished.
- The Bash shell provides plenty of programming constructs to developscripts that have a range from very simple to medium complexity.
Recommendations when porting scripts from Korn to Bash If you have existing Korn shell scripts that you want to port to Bash, you need to take into account the following: - The Korn "print" command is not available in Bash; use the "echo" command instead.
- You will need to change the first line of the script from:
#!/usr/bin/ksh to:#!/bin/bash
Back to top Creating Bash shell scripts for function testing These basic steps and recommendations can be applied to many client/server applications that run in Linux. - Document the prerequisites and main sequence for running scripts
- Divide actions into logical groups
- Develop an execution sequence based on a common usage scenario
- Provide comments and instructions in each shell script
- Make an initial backup to create a baseline
- Check for input parameters and environment variables
- Try to provide "usage" feedback
- Try to provide a "silent" running mode
- Provide one function to terminate the script when there are errors
- When possible, provide functions that do a single task well
- Capture the output of each script, while watching the output being produced
- Inside each script, capture the return code of each line command
- Keep a count of the failed transactions
- Highlight the error messages for easy identification in the output file
- When possible, generate files "on the fly"
- Provide feedback on the progress of the execution of the script
- Provide a summary of the execution of the script
- Try to provide an output file that is easy to interpret
- When possible, provide cleanup scripts and a way to return to the baseline
Each recommendation is detailed below along with a Bash shell script for illustration. To download this script, see theResources section later in this article. 1. Document the prerequisites and main sequence for running scripts It is important to document, preferably in a single file with a self-describing title (such as "README-testing.txt"), the main ideas behind the function testing, including the prerequisites, the setup for the server and the client, the overall (or detailed) sequence of the scripts to follow, how to check for success/failures of the scripts, how to perform the cleanup, and to restart the testing. 2. Divide the actions into logical groups If you have a very small list of actions to be performed, then you could put them all in a single shell script. However, if you have a large list of actions, it is good to group them into logical sets, such as the server actions in one file and the client actions in another. This way, you will have finer granularity to perform the testing and to maintain the test cases. 3. Develop an execution sequence based on a common usage scenario Once you have decided on the grouping of the actions, you need to think of performing the actions in a sequence that follows a common usage scenario. The idea is to simulate a real-life end-user situation. As a general rule, try to focus on the 20% of usage cases that test about 80% of the most commonly invoked functions. For example, let's assume that the application requires three test groups in a specific sequence. Each test group could be in a file, with a self-describing filename (where possible), and a number that helps to indicate the order of each file in the sequence, such as: 1. fvt-setup-1: To perform initial setup. 2. fvt-server-2: To perform server commands. 3. fvt-client-3: To perform client commands. 4. fvt-cleanup: To cleanup the temporary files, in order to prepare for the repetition of the above test cases. |
4. Provide comments and instructions in each shell script It is good coding practice to provide pertinent comments and instructions in the header of each shell script. That way, when another tester is assigned to run the scripts, the tester will get a good idea of the scope of the testing done in each script, as well as any prerequisites and warnings. An example is shown below, from the sample Bash script "test-bucket-1". #!/bin/bash # # Name: test-bucket-1 # # Purpose: # Performs the test-bucket number 1 for Product X. # (Actually, this is a sample shell script, # which invokes some system commands # to illustrate how to construct a Bash script) # # Notes: # 1) The environment variable TEST_VAR must be set # (as an example). # 2) To invoke this shell script and redirect standard # output and standard error to a file (such as # test-bucket-1.out) do the following (the -s flag # is "silent mode" to avoid prompts to the user): # # ./test-bucket-1 -s 2>&1 | tee test-bucket-1.out # # Return codes: # 0 = All commands were successful # 1 = At least one command failed, see the output file # and search for the keyword "ERROR". # ######################################################## |
5. Make an initial backup to create a baseline You may need to perform the function testing several times. The first time you run it, you will likely find some errors in your scripts or in the procedures. Therefore, to avoid wasting too much time in recreating the server environment from scratch -- especially if a database is involved -- you may want to make a backup just before starting with the testing. After you run the function test cases, then you could restore the server from the backup, and you would be ready for the next round of testing. 6. Check for input parameters and environment variables It is a good idea to validate the input parameters and to check if the necessary environment variables are properly set. If there are problems, display the reason for the problem and how to fix it, and terminate the script. The tester who is going to run this script will generally appreciate it if the script terminates shortly after being invoked in case a variable is not correct. No one likes to wait a long time in the execution of the script to find out that a variable was not properly set. # -------------------------------------------- # Main routine for performing the test bucket # --------------------------------------------
CALLER=`basename $0` # The Caller name SILENT="no" # User wants prompts let "errorCounter = 0"
# ---------------------------------- # Handle keyword parameters (flags). # ----------------------------------
# For more sophisticated usage of getopt in Linux, # see the samples file: /usr/lib/getopt/parse.bash
TEMP=`getopt hs $*` if [ $? != 0 ] then echo "$CALLER: Unknown flag(s)" usage fi
# Note quotes around `$TEMP': they are essential! eval(231, 243, 237); padding: 0px 3px; border-radius: 4px; overflow-wrap: break-word; text-indent: 0px;">CALLER=`basename $0` is used to get the name of the script being run. In that way, you do not need to hard-code the script name in the script. Thus, when you make a copy of the script, it will take less work to adapt the newly derived script. The statementTEMP=`getopt hs $*` is used to get the input arguments when the script is invoked (such as the -h for help and -s for silent mode).The statements[ -z "$X" ] andecho "The environment variable X is not set." andusage are used to test if the string is null (-z) and if so, then perform the echo statement saying that it is not set and invoke the "usage" function discussed below.If your script does not use flags, then you can use the variable "$#", which returns the number of arguments that are being passed to the script.7. Try to provide "usage" feedback It is a good idea to provide a "usage" statement that explains how to use the script: # ---------------------------- # Subroutine to echo the usage # ----------------------------
usage() { echo "USAGE: $CALLER [-h] [-s]" echo "WHERE: -h = help " echo " -s = silent (no prompts)" echo "PREREQUISITES:" echo "* The environment variable TEST_VAR must be set," echo "* such as: " echo " export TEST_VAR=1" echo "$CALLER: exiting now with rc=1." exit 1 } |
This "usage" statement can be called when the script is invoked with the "-h" flag, such as:./test-bucket-1 -h 8. Try to provide a "silent" running mode. You may want a script to have two running modes: - A "verbose" mode (you might want this as the default) in which the user is prompted to enter a value or to simply press Enter to continue.
- A "silent" mode, in which the user is not prompted for data.
The following excerpt illustrates the handling of the invocation flag "-s" to run the script in silent mode: # ------------------------------------------------- # Everything seems OK, prompt for confirmation # -------------------------------------------------
if [ "$SILENT" = "yes" ] then RESPONSE="y" else echo "The $CALLER will be performed." echo "Do you wish to proceed [y or n]? " read RESPONSE # Wait for response [ -z "$RESPONSE" ] && RESPONSE="n" fi
case "$RESPONSE" in [yY]|[yY][eE]|[yY][eE][sS]) ;; *) echo "$CALLER terminated with rc=1." exit 1 ;; esac |
9. Provide one function to terminate the script when there are errorsIt is a good idea to provide a central function to terminate the execution of the script when critical errors are encountered. This function could provide additional instructions on what to do in such situations: # ---------------------------------- # Subroutine to terminate abnormally # ----------------------------------
terminate() { echo "The execution of $CALLER was not successful." echo "$CALLER terminated, exiting now with rc=1." dateTest=`date` echo "End of testing at: $dateTest" echo "" exit 1 } |
10. When possible, provide functions that perform a simple task well For example, instead of issuing a big list of long line commands, such as: # -------------------------------------------------- echo "" echo "Creating Access lists..." # --------------------------------------------------
Access -create -component Development -login ted -authority plead -verbose if [ $? -ne 0 ] then echo "ERROR found in Access -create -component Development -login ted -authority plead" let "errorCounter = errorCounter + 1" fi
Access -create -component Development -login pat -authority general -verbose if [ $? -ne 0 ] then echo "ERROR found in Access -create -component Development -login pat -authority general" let "errorCounter = errorCounter + 1" fi
Access -create -component Development -login jim -authority general -verbose if [ $? -ne 0 ] then echo "ERROR found in Access -create -component Development -login jim -authority general" let "errorCounter = errorCounter + 1" fi |
... you could create a function such as the following, which also handles the return code and, if needed, increases the error counter: CreateAccess() { Access -create -component $1 -login $2 -authority $3 -verbose if [ $? -ne 0 ] then echo "ERROR found in Access -create -component $1 -login $2 -authority $3" let "errorCounter = errorCounter + 1" fi } |
... and then invoke this function in a manner that is easy to read and to expand: # ------------------------------------------- echo "" echo "Creating Access lists..." # -------------------------------------------
CreateAccess Development ted projectlead CreateAccess Development pat general CreateAccess Development jim general |
11. Capture the output of each script, while displaying the output being produced If the script does not automatically send the output to a file, you can exploit some features of the Bash shell to capture the output of the execution of the script, such as: ./test-bucket-1 -s 2>&1 | tee test-bucket-1.out |
Let's analyze the above command: - The "2>&1" command:Using "2>&1" , we redirect the standard error to standard output. The string "2>&1" indicates that any errors should be sent to the standard output, that is, the UNIX/Linux file id of 2 for standard error, and the file id of 1 for standard output. If you do not use this string, then you will be capturing only the good messages, and the error messages will not be captured.
- The pipe "|" and the "tee" command:There is a good analogy between the UNIX/Linux processes and simple plumbing concepts. In this case, we want to make a pipeline in which the input to the pipeline is the output of the desired script. The next thing to decide is what to do with the output of the pipeline. In this case, we want to capture it in an output file, named "test-bucket-1.out" in our example.
However, besides capturing the output, we also want to watch the output being produced while the script is running. To this end, we attach a "tee" (T-shape pipe) that permits two things at the same time: placing the output into a file AND displaying the output into the screen. The plumbing analogy would be:
process --> T ---> output file | V screen If you only want to capture the output and you do not want to see the output being displayed on the screen, then you can omit the extra plumbing: ./test-bucket-1 -s 2>&1 > test-bucket-1.out The plumbing analogy in this case would be: process --> output file 12. Inside each script, capture the return code of each line command One way to determine the success or failure of the function testing is by counting the line commands that have failed, that is, that have a return code different than 0. The variable "$?" provides the return code of the command recently invoked; in the example below, it provides the return code of the execution of the "ls" command. # ------------------------------------------- # The commands are called in a subroutine # so that return code can be # checked for possible errors. # ------------------------------------------- ListFile() { echo "ls -al $1" ls -al $1 if [ $? -ne 0 ] then echo "ERROR found in: ls -al $1" let "errorCounter = errorCounter + 1" fi } |
13. Keep track of the number of failed transactions One way to determine the success or failure in function testing is by counting the line commands that return a value other than 0. However, in my personal experience, I am accustomed to handling only strings in my Bash shell scripts, rather than integers. The manuals I consulted were not too clear on how to use integers, which is why I want to expand a little bit here on how to use integers and additions to count the number of errors (failures of line commands): First, you need to initialize the counter variable as follows:
Then, issue the line command and capture the return code using the $? variable. If the return code is different than 0, then increment the counter by one (see the statement in bold blue): ListFile() { echo "ls -al $1" ls -al $1 if [ $? -ne 0 ] then echo "ERROR found in: ls -al $1" let "errorCounter = errorCounter + 1"
fi } |
By the way, the integer variables can be displayed as other variables using "echo". 14. Highlight the error messages for easy identification in the output file When an error (or failed transaction) is encountered, besides increasing the error counter, it is a good idea to print an indication that there was an error. Ideally, the string of characters should have a substring such as ERROR or something similar (see the statement in bold blue), which will allow the tester to quickly find the error in the output file. This output file could be large, and it is important to quickly locate errors. ListFile() { echo "ls -al $1" ls -al $1 if [ $? -ne 0 ] then echo "ERROR found in: ls -al $1" let "errorCounter = errorCounter + 1" fi } |
15. When possible, generate files "on the fly" In some cases it is necessary to handle files that will be used by the application. You could use existing files or you could add statements in the script to create them. If the files to be used are long, then it is better to have them as separate entities. If the files are small and the contents simple or not relevant (the important point is to have a text file, regardless of its contents), then you could decide to create these temporary files "on the fly". The following lines of code show an example of how a temporary file is created "on the fly": cd $HOME/fvt
echo "Creating file softtar.c"
echo "Subject: This is softtar.c" > softtar.c echo "This is line 2 of the file" >> softtar.c |
The first echo statement uses the single > to force the creation of a new file. The second echo statement uses the double >> to append data to the bottom of an existing file. By the way, in case the file does not exist, then the file will be created. 16. Provide feedback on the progress of the execution of the script It is a good idea to include echo statements in the script to indicate the logical progress of its execution. You can add something that will quickly identify the purpose of the output. If the script is going to take more than few seconds to execute, you may want to print the date at the beginning and at the end of the execution of the script. This will allow you to compute the elapsed time. In the sample script, some echo statements that provide the indication of the progress are shown: # -------------------------------------------- echo "Subject: Product X, FVT testing" dateTest=`date` echo "Begin testing at: $dateTest" echo "" echo "Testcase: $CALLER" echo "" # --------------------------------------------
# -------------------------------------------- echo "" echo "Listing files..." # --------------------------------------------
# The following file should be listed: ListFile $HOME/.profile
...
# -------------------------------------------- echo "" echo "Creating file 1" # -------------------------------------------- |
17. Provide a summary of the execution of the script If you are counting the errors or failed transactions, it is good to indicate whether there were errors. The idea is that the tester could see the bottom of the output file and quickly tell if there were errors or not. In the following sample script, the code statements provide such a summary of the execution: # -------------- # Exit # -------------- if [ $errorCounter -ne 0 ] then echo "" echo "*** $errorCounter ERRORS found during ***" echo "*** the execution of this test case. ***" terminate else echo "" echo "*** Yeah! No errors were found during ***" echo "*** the execution of this test case. Yeah! ***" fi
echo "" echo "$CALLER complete." echo "" dateTest=`date` echo "End of testing at: $dateTest" echo ""
exit 0
# end of file |
18. Try to provide an output file that is easy to interpret It is very helpful to provide some key information in the actual output that is generated by the script. In that way, the tester could easily determine if the file that is being viewed is relevant and current. The addition of the date-time stamp is important to give a sense of currency. Also, the summary report helps to determine whether there were errors; if there were errors, then the tester will have to search for the specified keyword, such as ERROR, and identify the individual transactions that failed. A truncated sample output file is shown below: Subject: CMVC 2.3.1, FVT testing, Common, Part 1 Begin testing at: Tue Apr 18 12:50:55 EDT 2000 Database: DB2 Family: cmpc3db2 Testcase: fvt-common-1 Creating Users... User pat was created successfully. ...
Well done! No errors were found during the execution of this test case :) fvt-common-1 complete. End of testing at: Tue Apr 18 12:56:33 EDT 2000 |
An example of the bottom of the output file when errors are encountered is shown below: ERROR found in Report -view DefectView
*** 1 ERRORS found during the execution of this test case. *** The populate action for the CMVC family was not successful. Recreating the family may be necessary before running fvt-client-3 again, that is, you must use 'rmdb', 'rmfamily', 'mkfamily' and 'mkdb -d', then issue: fvt-common-1 and optionally, fvt-server-2. fvt-client-3 terminated, exiting now with rc=1. End of testing at: Wed Jan 24 17:06:06 EST 2001 |
19. When possible, provide cleanup scripts and a way to return to the baseline The test scripts may generate temporary files; in that case, it is a good practice to have a script that will delete those temporary files. This will avoid mistakes in which the tester may not delete all the temporary files, or worse, delete some needed files that were not temporary. Back to top Running the function-testing Bash shell script This section describes how to run the Bash shell scripts for function testing. I'm assuming that you've executed all the steps in the previous sections. Setting up required environment variables Specify the following environment variables in the .profile or manually on demand. This variable is used to illustrate how to handle in the script, the verification that required environment variables must be defined prior to running the script.
Copying the Bash shell scripts into the proper directory The Bash shell scripts and the associated files need to be copied into the directory structure of the user id who is going to conduct the function testing. - Log into the account. You should be in the home directory. Let's assume that it is /home/tester.
- Create a directory for the test cases:
mkdir fvt - Copy the Bash shell scripts and the associated files. Obtain the zip file (seeResources) and place it under $HOME. Then unzip it as follows:
unzip trfvtbash.zip - Change the proper file permissions, in order to execute the files:
chmod u+x * - Change the name to remove the file suffix:
mv test-bucket-1.bash test-bucket-1
Running the script To run the script, perform the following: - Log into the tester user id.
- Change to the directory where the scripts were copied:
cd $HOME/fvt - From $HOME/fvt run the script:
./test-bucket-1 -s 2>&1 | tee test-bucket-1.out - Look at the bottom of the output file "test-bucket-1.out" and see the conclusion of the summary report.
Resources - Download trfvtbash.zip, which contains the sample code and tools referenced in this article. The tools might be updated in the future.
- To unzip the files, try the Info-ZIP software. Because of the general value of the tools, it is recommended that you add the unzip and zip tools in a directory in the PATH that is accessible to all the users for the machine.How to unzip the files:To view the contents of the zip file (without actually unpackaging and uncompressing the files), do:
unzip -l trfvtbash.zip To unpackage and uncompress the zip file, do:unzip trfvtbash.zip - Read Daniel Robbins' three-part series on bash programming ondeveloperWorks:Part 1,Part 2, andPart 3.
- VisitGNU's bash home page.
About the author
Angel Rivera is an advisory software engineer with the VisualAge TeamConnection technical support team, where he is currently the team lead. He has an M.S. in Electrical Engineering from The University of Texas at Austin, and a B.S. in Electronic Systems Engineering from the Instituto Tecnologico y de Estudios Superiores de Monterrey, Mexico. He joined IBM in 1989. He can be reached at[email protected] In developing this article, Angel would like to acknowledge the contribution of Lee Perlov in WebSphere technical support.
reresources : #!/bin/bash # # Name: test-bucket-1 # # Purpose: # Performs the test-bucket number 1 for Product X. # (Actually, this is a sample shell script, which invokes some # system commands to illustrate how to construct a Bash script) # # Notes: # 1) The environment variable TEST_VAR must be set (as an example). # 2) To invoke this shell script and redirect standard output and # standard error to a file (such as test-bucket-1.out) do the # following (the -s flag is "silent mode" to avoid prompts to the # user): # # ./test-bucket-1 -s 2>&1 | tee test-bucket-1.out # # Return codes: # 0 = All commands were successful # 1 = At least one command failed, see the output file and search # for the keyword "ERROR". # ######################################################################.#########
# ---------------------------- # Subroutine to echo the usage # ----------------------------# ----------------------------
usage() { echo "USAGE: $CALLER [-h] [-s]" echo "WHERE: -h = help " echo " -s = silent (no prompts)" echo "PREREQUISITES:" echo "* The environment variable TEST_VAR must be set, such as: " echo " export TEST_VAR=1" echo "$CALLER: exiting now with rc=1." exit 1 }
# ---------------------------------- # Subroutine to terminate abnormally # ----------------------------------
terminate() { echo "The execution of $CALLER was not successful." echo "$CALLER terminated, exiting now with rc=1." dateTest=`date` echo "End of testing at: $dateTest" echo "" exit 1 }
# --------------------------------------------------------------------------- # --------------------------------------------------------------------------- # The commands are called in a subroutine so that return code can be # checked for possible errors. # ---------------------------------------------------------------------------
ListFile() { echo "ls -al $1" ls -al $1 if [ $? -ne 0 ] then echo "ERROR found in: ls -al $1" let "errorCounter = errorCounter + 1" fi }
################################################################################
# -------------------------------------------- # Main routine for performing the test bucket # --------------------------------------------
CALLER=`basename $0` # The Caller name SILENT="no" # User wants prompts let "errorCounter = 0" let "errorCounter = 0"
# ---------------------------------- # Handle keyword parameters (flags). # ----------------------------------
# For more sophisticated usage of getopt in Linux, see # the samples file: /usr/lib/getopt/parse.bash TEMP=`getopt hs $*` if [ $? != 0 ] then echo "$CALLER: Unknown flag(s)" usage fi
# Note the quotes around `$TEMP': they are essential! eval set -- "$TEMP"
while true do case "$1" in -h) usage "HELP"; shift;; # Help requested -s) SILENT="yes"; shift;; # Prompt is not needed --) shift ; break ;; *) echo "Internal error!" ; exit 1 ;; esac done
# ------------------------------------------------ # The following environment variables must be set# ------------------------------------------------ # The following environment variables must be set # ------------------------------------------------
[ -z "$TEST_VAR" ] && { echo "The environment variable TEST_VAR is not set."; usage; }
# -------------------------------------------------- # Everything seems to be OK, prompt for comfirmation # --------------------------------------------------
if [ "$SILENT" = "yes" ] then RESPONSE="y" else echo "The $CALLER will be performed." echo "Do you wish to proceed [y or n]? " read RESPONSE # Wait for response [ -z "$RESPONSE" ] && RESPONSE="n" fi
case "$RESPONSE" in [yY]|[yY][eE]|[yY][eE][sS]) ;; *) echo "$CALLER terminated with rc=1." exit 1 ;; esac# -------------------------------------------------- echo "Subject: Product X, FVT testing" dateTest=`date` echo "Begin testing at: $dateTest" echo "" echo "Testcase: $CALLER" echo "" # --------------------------------------------------
# -------------------------------------------------- echo "" echo "Listing files..." # --------------------------------------------------
# The following file should be listed: ListFile $HOME/.profile
# The following file should NOT be listed: ListFile test-1
# -------------------------------------------------- echo "" echo "Creating file 1" # --------------------------------------------------
echo "This is file: test1" > test1 if [ $? -ne 0 ] thenif [ $? -ne 0 ] then echo "ERROR found in: creating file test1" let "errorCounter = errorCounter + 1" fi
# -------------- # Exit # -------------- if [ $errorCounter -ne 0 ] then echo "" echo "*** $errorCounter ERRORS found during the execution of this test case. ***" terminate else echo "" echo "*** Yeah! No errors were found during the execution of this test case. Yeah! ***" fi
echo "" echo "$CALLER complete." echo "" dateTest=`date` echo "End of testing at: $dateTest" echo ""
exit 0
|
上一篇:shell 知识点补充(4)-date/数值运算/test 指令/判断符号 [ ]/预设变数($0)/条件判断:if then
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
全部评论
()
最热
最新
相关文章
-
【Bash Scripts】
一. shell脚本基础Bash脚本类似批处理,简单来讲就是把许多的指令集合在一起,并提供循环、条件、判断等重要功能,语法简单实用,用以编写程序,大大简化管理员的操作,并可以完成图形工具所无法实现的功能。1. 创建包含ba...
BASH
完整版
脚本
-
Bash scripts
创建新shell脚本1. 创建包含bash命令的文本文件。文件的第一行应为:#!/bin/bash2. 使文件可执行(使用chmod +x scripts)3. 将文件放置在用户的$PATH的目录中~/bin – 用于用户的私有程序/usr/local/bin – 本地开发、...
redhat
-
Shell Scripts - 条件语句,case语句,function功能
改动之前的代码 1.推断 $1 是否为 hello,假设是的话。就显示 "Hello, how are you ?"; 2.假设没有加不论什么參数。就提示使用者必需要使用的參数下达法; 3.而假设增加的參数不是 hello ...
程序段
服务端
实际案例
变量名
其他
-
[React Testing] Debug the DOM State During Tests using React Testing Library’s debug Function
While you’re writing your tests it can be helpful to see what the DOM looks like. You can do this with React Testing Library’s debug function which will log a formatted and syntax highlighted state...
[React Testing]
-
Bash File Testing
-b filename Block special file-c filename Special character file-d directoryname Check for directory existence-e filename Check for file existence-f filename Check for regular file existenc...
代码
-
How to Use the BASH "for" Loop in Shell Scripts
BASH (which stands for Bourne Again Shell) is a scripting language utilized by most Linux and UNIX-based operating systems.You can run BASH commands within a terminal window one after the other or you...
BASH
Loop
Shell Scripts
-
bash-shell-scripts高级脚本配置IP地址
[root@kongxl shell]# cat mod_ip_hostname.sh #!/bin/bash#Auto modify ip and hostname#by colin on 2015-05-07IP_CONFIG='/etc/sysconfig/network-...
shell
bash
scripts
-
shell scripts
现在有一个文件aa.txt ,其实现格式如下,而我想实现的结果是192.168.1.17 down[root@localhost shell]# cat aa.txt 192.168.1.17down192.168.1.103open192.168.1.221open192.168.1.104down192.168.1.175down192.168....
scripts
lshell
-
using in the function
Class aa { public aa() public void kk() { } } class D : IDisposable { ...
代码
-
RH033 Unit6 Using the bash shell
Objectives 1) Upon completion of this unit, you should be able to: - Use command-line shortcuts - Use command-line expansion - Use history and editing tricks - Use the gnome-terminal Command...
shell
休闲
bash
Using
RHCE
-
shell scripts and skills
1 .快速从主机名的得到ip地址: ping -q -c1 centos1 | awk '{print $3}' | sed -n 's/[()]//pg' 2. 现有文本文件日志:游戏id 在线时...
职场
shell
休闲
scripts
skills
-
学习shell scripts
变量赋值使用declare -i 定义整型类[root@daniel scripts]# aa=5+6[root@daniel scripts]# echo $aa5+6[root@daniel scripts]# declare -i aa[root@daniel s...
shell
其他
-
Running .sh scripts in Git bash
Running .sh scripts in Git bashLet's say you have a script script.sh. To run it (using Git Bash), you do the followingchmod +x script.sh./script.shYou can change the chmod to the executable per...
git
bash
其他
-
Linux之linux bash scripts
Linux之linux bash scripts...
函数
for
if
sed
while
awk
-
[Bash] Create and Run Bash Scripts with Command Line Arguments
Create a scriptSee Chmod.md, how to create a sh file and modify premisson to exec mode.ParametersParamters are referred by $1, $2....For example:echo "Hello $1"Run:./script.sh WanIt print H...
git
json
Bash
-
[SHELL]shell scripts笔记(2)
最近一直在研究shell脚本,整理了些比较有用的以备不时之需。。1.获取字符串长度# var=1234567890# echo ${#var}2.识别当前shell版本# echo $SHELL# echo $03.检查是否为超级用户-------------------------#!/bin/ba...
shell
scripts
-
[SHELL]shell scripts笔记(1)
自己没事总结了点基础的东西,以备不时之需。一.判断式:1.判断符号 &&及||检测test是否存在:# test -e /haha注:test是一个判断文件属性的命令,-e参数判断目录是否存在,执行结果不会显示任何信息,但最后...
shell
-
jsp shell testing
jspshell
51cto
jspshelltest
-
bash脚本-function
脚本编程之函数:function: 功能结构化编程,不能独立运行,需要调用时执行,可以被多次调用定义一个函数:function FUNCNAME { command}FUNCNAME() { command}自定义执行状态返回值:return #0-255接受...
function
|