博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何进行shell脚本正确性测试
阅读量:3623 次
发布时间:2019-05-21

本文共 8038 字,大约阅读时间需要 26 分钟。

在实际工作中,需要对shell脚本进行正确性测试。

如何用最快最有效的方式进行测试?

很多开发的习惯是,二话不说,写完/拿到,就跑一把,看看输入,输出,想要的操作是否完成,也就过了。

其实这是十分不严谨的,若是未经过QA,风险还是相当大的。

以下即shell脚本测试流程,仅供参考

1.代码走读:

    写完,或者拿到一个shell脚本,不必急于运行,虽然实践是检验整理的唯一标准,但是,在读代码这个过程中,可以规避很多低级的bug.

    读什么?

    A.代码逻辑,这个脚本用来做什么,主要分为多少步,分别做了什么事情?

        用于检查是否有遗漏逻辑,或有悖于需求。

    B.具体语法,变量,判断语句

        语法方面的东西,变量是否定义,判断语句逻辑是否正确,是否考虑各种异常,错误是否退出,返回正确状态值等。

2.语法检测:

    shell的语法还是相当让人无语的,很多很容易疏忽遗漏的地方

    命令格式: sh -n ***.sh 

    

    若是没有异常输出,证明脚本没有明显的语法问题。

3.运行跟踪:

   实践是检验整理的唯一标准,跑一把。

   不过,可不是直接运行然后去看最终结果,这样会遗漏掉很多中间过程。

   命令格式: sh -vx ***.sh

   得到效果如下:

我们可以看到

每行代码原始命令(无+的):[这是-v的效果]

代码执行时的情况(带+),包括运算结果,逻辑判断结果,变量赋值等等[-x的效果]

而我们所要关注的就是这些信息,主要是变量值和逻辑判断结果。

4.覆盖分支:

   直接跑,只能覆盖到主体流程,对于其他控制流分支的代码是无法覆盖到的。

   对于关键性的,重点的逻辑,我们需要制造条件,使运行脚本可以进入对应分支

5.其他:

   A.关于bashdb:

      可以尝试下,但是感觉投入产出比不高

   B.关于单元测试:

      实际工作中,由于项目压力比较大,单元测试的成本还是相当高的,所以目前为止没有。

6.有没有更好的方式?

    好吧,单步跟踪,脚本短的还好,日志信息不会太多,要是多了,存在调用其他脚本等等.....

    日志量达到几千行,这是很轻易的事情。

    跟踪过的童鞋有同感,展现不够友好,惨白惨白一片,一千行下来,看的眼花。

    很容易遗漏。

    So.进行了一层优化,对日志进行处理,使用正则,标注我关心的信息

    效果图对比:

    

处理后:(对错误,关键信息进行颜色标记,在linux终端可以显示)

   

      

脚本是用python实现的,位置:

思想是:执行,抓到所有日志,用正则进行匹配,打上颜色,然后输出。

代码如下:

#!/bin/env python#-*- coding:utf-8 -*-#@Author: wklken#@Mail: wklken@yeah.net ,lingyue.wkl@taobao.com#@Date: 20120706#@Version: 0.1  sh -n, check for static syntax#          0.2  sh -vx, color the output log which i care about#          0.2.1 rebuild all functions , lines  200+ -> 120#          0.2.2 refine the re pattern.#          0.2.3 add sh params support. fix bug and add re patterns#          0.2.5 add warn/error pattern and collect the result#          0.2.6 use decorator to refine print, refine collect method#@Desc: Quick test shell script.The target is hacking into it and get all the status i need.#TODO: need to keep source code in 200 lines! refine!import sys,osimport commandsimport re#color definedCOLOR_NONE = "C_NONE"COLOR_GREEN = "C_G"COLOR_RED = "C_R"COLOR_YELLOW = "C_Y"COLOR_PURPLE = "C_P"COLOR_BLUE = "C_B"COLOR_MAP = {COLOR_NONE : "\033[m",             COLOR_GREEN : "\033[01;32m",             COLOR_RED : "\033[01;31m",             COLOR_YELLOW : "\033[01;33m",             COLOR_PURPLE : "\033[01;35m",             COLOR_BLUE : "\033[01;34m",             None:"\033[m" }#the command used definedSH_N = "sh -n "SH_X = "sh -vx "LOG_BEGIN = "export PS4='+${BASH_SOURCE}|${LINENO}|${FUNCNAME[0]} -> ';"LOG_BEGIN = ""#the type of output log lineLINE_TYPE_CMD = "CMD"LINE_TYPE_EXC = "EXC"LINE_TYPE_CMT = "CMT"CMD_Y = COLOR_MAP.get(COLOR_YELLOW) + "CMD: " + COLOR_MAP.get(COLOR_NONE)#----------pattern used to match begin -----------------------------#0. specialPATTERN_ADDSIGN = re.compile("(^\++)")#1. execute command log match patternexc_mark_pattern = [(r"([\[\]])", COLOR_YELLOW), #for condition testing   must be the first one                    (r"(([12]\d{3})(1[12]|0[1-9])(0[1-9]|1\d|2\d|3[01]))",COLOR_PURPLE), #date yyyyMMDD                    (r"(tbsc-dev)", COLOR_RED),  # path: tbsc-dev                    (r"([a-zA-Z_][a-zA-Z0-9_]*=[\s|\"\"]*)$",COLOR_RED),   # params=None                    (r"(exit\s+-?\d*|return\s+-?\d*)",COLOR_BLUE), #exit status                    (r"(\s(\-[acbdefgnorsuwxzL]|\-(lt|le|gt|ge|eq|ne))\s)", COLOR_YELLOW),                    (r"((\s(=|==|<=|>=|\+=|<|>|'!='|\&\&)\s)|'!')", COLOR_YELLOW),                    (r"(\s(\-input|\-output|\-i|\-o)\s)", COLOR_YELLOW),                    ]EXC_MARK_PATTERN = [(re.compile(s),color) for s,color in exc_mark_pattern]#2. error/warn result log match pattern# 100% errorerror_mark_pattern = [(r"(No such file or directory|command not found|unknown option|invalid option)",COLOR_RED), #result -> file not found                    (r"(unary operator expected)",COLOR_RED), # test failed                    (r"(Permission denied)",COLOR_RED),                    (r"(syntax error|unexpected|read error)",COLOR_RED),                    (r"(java.io.FileNotFoundException|org.apache.hadoop.mapred.InvalidInputException|java.lang.IllegalMonitorStateException)", COLOR_RED),#javaerror                    ]ERROR_MARK_PATTERN = [(re.compile(s),color) for s,color in error_mark_pattern]# may be not error ,just warn,noticewarn_mark_pattern = []WARN_MARK_PATTERN = [(re.compile(s),color) for s,color in warn_mark_pattern]#3. command log match patterncmd_mark_pattern = error_mark_pattern + warn_mark_pattern + \                    [                    (r"(line \d+)", COLOR_RED), #error report the line No                    (r"(\$(\{\w+\}))", COLOR_PURPLE),                    (r"(\.\.)",COLOR_PURPLE), #相对路径                    (r"((?
>|<|>)", COLOR_YELLOW), ]CMD_MARK_PATTERN = [(re.compile(s),color) for s,color in cmd_mark_pattern]#----------pattern used to match end -----------------------------#static params definederror_lines = []#functions begindef str_coloring(str_info, color=COLOR_NONE): """color str""" return COLOR_MAP.get(color, COLOR_MAP.get(None)) + str_info + COLOR_MAP.get(COLOR_NONE)def print_symbol(str_info): """print the symbol""" print "-"*20 + str_info + "-"*20def wrap_print_func(arg): """wrap func, print begin and end sign""" def newfunc(func): def newfunc_withparams(*args, **kwargs): print_symbol(arg+" BEGIN") func(*args, **kwargs) print_symbol(arg+" END") return newfunc_withparams return newfunc@wrap_print_func("STATIC SYNTAX")def static_syntax_check(file_path): """Check the static syntax""" cmd = SH_N + file_path result = commands.getoutput(cmd) if result: print "script syntax check:"+str_coloring(" FAILED", COLOR_RED) print str_coloring(result,COLOR_RED) else: print "script syntax check:"+str_coloring(" PASS", COLOR_GREEN)def pre_handler(result): """pre handle the result lines """ pass@wrap_print_func("PROCESS LOG CHECK")def dynamic_log_process(file_path, params): """Process the log of sh script""" cmd = LOG_BEGIN + SH_X + file_path + " " + params result = commands.getoutput(cmd) pre_handler(result) process_line(result)def cmd_type(line): """return the type of line,and can do something with it""" if line.startswith("+"): return LINE_TYPE_EXC,line elif line.lstrip().startswith("#"): return LINE_TYPE_CMT,line else: #return LINE_TYPE_CMD, CMD_Y + line return LINE_TYPE_CMD,linedef mark_sign_by_pattern(line, line_type=LINE_TYPE_EXC): """mark the str by pattern""" #can't use in py2.4,ni mei a #use_pattern = EXC_MARK_PATTERN if line_type == LINE_TYPE_EXC else CMD_MARK_PATTERN if line_type == LINE_TYPE_EXC: use_pattern = EXC_MARK_PATTERN else: use_pattern = CMD_MARK_PATTERN native_line = line for pt,color in use_pattern: m = pt.findall(line) if m: line = pt.sub( COLOR_MAP.get(color)+r"\1"+COLOR_MAP.get(COLOR_NONE), line) for pt,color in ERROR_MARK_PATTERN: e = pt.findall(native_line) if e: error_lines.append(line) return linedef process_line(result): """format each line.With the pattern""" lines = result.split("\n") for line in lines: line_type, line = cmd_type(line) if line_type == LINE_TYPE_EXC: result = mark_sign_by_pattern(line, line_type) print PATTERN_ADDSIGN.sub(COLOR_MAP.get(COLOR_GREEN)+r"\1"+COLOR_MAP.get(COLOR_NONE),result) elif line_type == LINE_TYPE_CMD: print mark_sign_by_pattern(line, line_type) elif line_type == LINE_TYPE_CMT: print line@wrap_print_func("RESULT COLLECT")def warn_error_collect(collect_list, collect_type="ERROR"): print str_coloring("RESULT TYPE: " + collect_type, COLOR_GREEN) if len(collect_list): print str_coloring(collect_type+" FOUND: ", COLOR_RED) + str_coloring(str(len(collect_list)), COLOR_YELLOW) for line in collect_list: print line else: print str_coloring("NO " + collect_type + " FOUND", COLOR_GREEN)args = sys.argv[1:]sh_name = args[0]params = " ".join(args[1:])static_syntax_check(sh_name)dynamic_log_process(sh_name, params)warn_error_collect(error_lines, "ERROR")

工具的实现是为了提高效率,节约时间。
到此结束。

原文地址:

转载地址:http://akkun.baihongyu.com/

你可能感兴趣的文章
9、软件安装:虚拟机的使用与安装操作系统
查看>>
10、软件安装:安卓模拟器的安装与使用
查看>>
11、远程管理:系统自带3389远程桌面管理工具
查看>>
12、远程管理:TeamViewer远程管理工具
查看>>
13、网站搭建:如何建立自己的个人网站
查看>>
14、数据管理:搭建公司内部FTP服务器
查看>>
15、网站管理:网站源代码上传方法
查看>>
就业指导:电脑工程师的需求分析和就业指导
查看>>
1、入门必备!DOS命令之系统常用命令
查看>>
2、服务器系统:Windows Server 2012 操作系统
查看>>
3、服务器系统:Windows Server 2019 操作系统
查看>>
4、网络管理:系统集成之IIS服务器搭建
查看>>
5、网络管理:系统集成之FTP服务器搭建
查看>>
6、网络管理:WinMail邮件服务器的搭建方法
查看>>
7、网络管理:ARP防范、带宽控制、补丁、监控上网
查看>>
8、端口管理:23远程端口的入侵与防范
查看>>
9、端口管理:3389远程端口的入侵与防范
查看>>
10、安全配置:服务器防火墙设置和端口的封闭
查看>>
11、安全配置:服务器IP筛选过滤策略
查看>>
12、安全配置:服务器防火墙过滤黑客攻击IP
查看>>