代码检查摘要:代码检查是白盒测试的一种静态测试方法,是众多软件测试方法中发现软件缺陷最有效的方法之一。本文结合国内外学者在相关领域的研究情况,介绍代码检查相关的基本概念、过程和分析方法。关键字:白盒测试,代码检查,静态分析,检查规则一、引言按照测试时源代码是否可见,软件测试可以分为白盒测试和黑盒测试两类。白盒测试(结构测试),即逻辑驱动的测试,是在了解程序内部结构的基础上,对程序的逻辑结构进行检查,从中获取测试数据。白盒测试关注的是测试用例执行的程度或覆盖程序逻辑结构的程度。白盒测试一般只应用于软件开发阶段。白盒测试,又可按照是否需要运行程序,进一步细分为了静态测试和动态测试两种。通常情况下是按照先静态后动态测试顺序来实施。其中,静态测试包括代码检查、静态结构分析、代码质量度量等测试内容。静态测试既可以由人工进行,充分发挥人的逻辑思维优势,也可以借助软件工具自动进行。代码检查是一种对程序代码进行静态检查。传统的代码检查是通过人工阅读代码的方式,检查软件设计的正确性;用人脑模拟程序在计算机中的运行,仔细推敲、校验和核实程序每一步的执行结果,进而判断其执行逻辑、控制模型、算法和使用参数与数据的正确性。在实践中,代码检查比动态测试更有效率,能找到更多的缺陷,通常能发现30%~70%的逻辑设计和编码缺陷。代码检查非常耗费时间,而且需要专业知识和经验的积累。代码检查定位在编译之后和动态测试之前进行,在检查前,应准备好需求描述文档、程序设计文档、程序的源代码清单、代码编码标准和代码缺陷检查表等。代码检查可以发现的软件问题包括:声明或引用错误、函数/方法参数错误、语句不可达错误、数组越界错误、控制流错误、界面错误和输入/输出错误等。1、代码检查代码检查包括桌面检查、代码走查和代码审查等方式,主要检查代码和设计的一致性,代码对标准地遵循、可读性,代码逻辑表达的正确性,代码结构的合理性等方面;发现违背程序编写标准的问题,程序中不安全、不明确和模糊的部分,找出程序中不可移植部分、违背程序编程风格的问题,包括变量检查、命名和类型检查、程序逻辑检查、程序语法检查和程序结构检查等内容。下面对代码检查的三种具体方式进行介绍。桌面检查是一种传统的检查方法,由程序员检查自己编写的程序。程序员在程序通过编译之后对源代码代码进行分析、检验,并补充相关的文档,目的是发现程序中的错误。代码走查代码走查就是针对代码,在假想的输入情况下,逐行的浏览代码,走查代码中潜在的缺陷并记录结果的过程。代码走查以小组会议方式进行,每小组3-5人。与代码审查不同的是,走查要求与会者扮演计算机的角色让测试用例沿被测程序的逻辑运行,是在模拟动态测试;而代码审查更多的是静态测试。代码审查代码审查是由一组人通过阅读、讨论和争议对程序进行静态分析的过程,以小组会的方式进行。审查小组一般由若干程序员(包括程序代码的设计者)和代码检查人员组成。会前把设计规格说明书、控制流程图、程序文本以及要求、规范、错误检查清单交给与会者,开会时程序作者朗读解释程序,其他人则集中精力,捕捉程序在结构、功能、编码风格等方面的问题。2、代码检查项代码检查项即检查代码时,指定需要进行检查的内容。具体如:检查变量的交叉引用表;检查标号的交叉引用表;检查子程序、宏、函数;等价性检查;标准检查;风格检查;选择、激活路径;对照程序的规格说明,详细阅读代码,逐字逐句分析;补充文档。检查项可以作为依据,用来编制代码规则、规范和缺陷检查表等。3、编码规范编码规范是程序编写过程中必须遵循的一套事先约定或者已经制度化、标准化的规则集,一般会详细的规定代码的语法规则和语法格式。一个良好的编码规范能够带来许多好处:改善代码质量;提高开发进度;增进团队精神。对于软件开发而言,采用好的编程规范,虽然不能彻底杜绝糟糕的代码产生。但对于代码检查和将来的代码维护,仍然是意义重大的。4、缺陷检查表在进行人工代码检查时,使用代码缺陷检查表作为代码检查的参考依据。在软件测试项目实践中代码缺陷检查表又常被称作代码检查清单。代码缺陷检查表中一般包括开发人员容易出错的地方和在以往的工作中遇到的典型错误。对应于不同的编程语言,代码缺陷检查表的具体内容将会有所不同。例如:对于C/C++语言代码缺陷检查表内容有以下几部分:文件结构;文件的版式;命名规则;表达式与基本语句;常量;函数设计;内存管理;C++函数的高级特性;类的构造函数、析构函数和赋值函数;类的高级特性;其他的常见问题等。5、代码检查规则在代码检查中,需要依据被测软件的特点,选用适当的标准与规范。在使用测试软件进行自动化代码检查或辅助代码检查时,测试工具需要内置许多编码规范。不同编程语言,对应的检查规范有所不同。针对与C/C++语言的规则有以下几类规则:通用规则、C++编码规则、C编码规则、Meyers-Klaus规则以及自定义规则。使用时,需要根据编程语言和被测程序的特点,选择适当的规则进行检查。6、静态分析静态分析是不执行程序,而分析程序代码的过程。源代码被静态分析器分析之后,得到的静态分析结果,通常可以表示成一棵静态语法树。其中包含了被测项目源代码的静态结构信息:基本代码成分、程序结构、语句结构、类型和模板等信息。程序代码静态分析的结果能够给代码检查提供帮助。三、代码检查过程传统的代码检查是一种静态检查程序的测试方法,通常以团队的形式来进行。检查团队由程序作者,一个负责人,一个记录员以及一些检查员组成。首先需要一系列的准备工作,包括参与者的挑选和材料的准备。然后是个人准备阶段,每个小组成员各自熟悉材料。个人准备阶段后,就是实际的检查会议。在会议上,检查小组在假想的输入下,由程序作者带领,逐行的浏览代码,评审代码中潜在的缺陷。检查小组根据发现缺陷的严重程度和类型对其进行分类,并将问题记录下来供作者修正。会议后是作者的返工,作者汇报每个缺陷,最后确认每个缺陷已经被陈述过了。图11为传统的代码检查过程。图1代码检查过程示意图代码检查过程中的两个重要阶段“个人准备”和“召开会议”阶段有以下注意事项:1、“个人准备”阶段:会前准备阶段是检查过程的一个关键阶段,因为如果检查者没有为检查做好充分的准备,检查效果会大打折扣。如果有检查人员没有做好准备,主审员可取消其代码检查资格,甚至取消这次检查会议。检查人员要熟悉检查内容的相关文档,了解程序背景、设计思想和编程方法,在读懂、“吃”透代码的基础上,查出尽可能多的错误。2、“召开会议”阶段:参与会议的检查者应具有一定的专业技能和经验,缺乏经验的检查人员必然缺乏合适的领域知识来深入理解材料;参与会议的检查者应做充分的个人准备,没有做充分准备的检查人员不能在检查会中做出实质性的贡献;检查会议的速度应进行控制,如果试图在短时间内处理太多的材料,检查效果也会大打折扣。现在较为常见的代码检查速度上的建议为:汇编代码150行/小时,C语言150行/小时,而对于C++、Java这种面向对象语言,代码检查速度可以提高到200-300行/小时。由此可见,代码检查适合于采用工具辅助的特性有:文档处理,个人准备,会议支持,数据收集。文档处理这是工具可支持的最明显的领域。传统的检查要求分发每份文档的复印件等,而将纸质的文档替换成计算机式的文档,不只是简单的介质变更,更是提供了一种契机——提高文档的可用性和表示性的机遇。个人准备首先,自动的缺陷检测可以用来发现简单的缺陷。如果简单问题能被自动发现,检查员就能专注于更加复杂/困难的缺陷,以及那些不能被自动发现的、潜在的、可能带来更大影响的问题。另外,自动化工具应该对个人准备阶段提供更多的帮助。例如,检查员可以利用检查表以及其它支持文档,并能很容易地交叉引用它们;还有些代码辅助理解工具,可为检查员理解程序、了解程序结构提供帮助。会议支持一些成员由于某些原因,可能没有花费足够的时间来进行准备,但他们仍然参加会议并试图掩盖他们的过失。项目管理人员可以使用计算机监控的个人准备时间信息,来剔除那些没有做好个人准备的成员,或者督促他们投入更多的努力。召开会议时,检查员通常面对的是一堆枯燥的程序代码,如果在代码之外再结合一些图、表等便于分析、理解代码的信息,相信检查会议可以进行得更加有序和高效。数据收集代码检查一个重要的部分就是度量信息的收集,用来提供反馈以改进检查过程。度量信息包括会议时间、发现的缺陷、检查花费的总时间等。根据这些数据,可以来评价每一次代码审查的质量,进而给出关于代码审查的改进建议。通过对检查过程的部分阶段提供计算机支持,代码检查可以进行得更加有效。使用计算机来支持检查过程,可以提高效率,并增加检查过程的严格性。四、代码检查历史数据代码检查中的历史数据本质是软件问题(缺陷)。按照不同的代码检查角度,存在多种对缺陷分类的方法。对过往发现的软件问题进行分析,总结出今后对于类似的代码需要按照某种规则来加以检查,这种的规则就是检查清单上的一条清单项,代码检查清单就是大量规则的集合。此外,由于软件问题总是以软件问题报告为载体形式出现,因此软件问题报告也被通俗的理解为代码检查历史数据。下面对缺陷分类、代码检查清单和软件问题报告加以研究。1、缺陷分类关于缺陷分类存在以下几种常见的划分方式:1)按缺陷出现的区域分类这种分类方式是最常见的缺陷分类方式。按照出现区域将代码缺陷划分为变量级、属性级、函数/方法级和类级缺陷。其中,变量级、属性级和部分函数/方法级的缺陷,与传统的面向过程编程中的缺陷分类基本一致;而多数方法级缺陷和类级缺陷,则是针对面向对象技术编程特点提出的。2)按检测内容分类分为冲突、一致性问题两种。冲突对应于文献[1]中的基于确定性“信念”的判定,而一致性问题则对应于基于可能性“信念”的判定。3)按对代码的危害分类按照对代码的危害,一般分为浪费时间和空间;语义混淆;暴露封装性,扩大使用权限;程序一致性问题;程序约束条件问题和空指针问题等。2、代码检查清单(Checklist)代码检查过程中,代码检查人员都会有一份代码检查清单。代码检查清单是一份为代码检查人员准备的缺陷检查表,检查表中开列所有可能与代码有关的缺陷,并注明了检查的内容、缺陷类型以及严重性。检查清单是检查代码的依据,代码检查人员根据它来发现并判断问题。代码检查清单中会逐条列出所有应该检查的缺陷种类,以及每条缺陷的各种特征,并且根据缺陷的严重程度和类型对其进行分类。通常每一条缺陷的特征描述如下:1)缺陷描述:该缺陷的问题描述、举例说明,以及相应的正确形式;2)缺陷出现的区域:分别为表达式级、语句级、声明级、模板缺陷、预处理缺陷、类级缺陷以及性能缺陷。表达式级、语句级、声明级以及预处理的缺陷,主要面向过程程序中的缺陷;模板缺陷、类级缺陷,则是针对面向对象软件的特点提出的;代码冗余等归为性能缺陷;3)缺陷对代码的危害:代码中出现某种缺陷将会造成什么样的影响。例如,检查表中一条缺陷的特征描述如下:问题描述:指针所指内存释放后没有将指针赋为NULL。举例说明:char*p=(char*)malloc(100);strcpy(p,hello);free(p);//p所指的内存被释放,但是p所指的地址还是不变…if(p!=NULL)//没有起到防错的作用{strcpy(p,world);//出错}正确形式:在释放内存的同时将指针置空。char*p=(char*)malloc(100);strcpy(p,hello);free(p);p=NULL;//增加指针置空语句…if(p!=NULL){strcpy(p,world);}出现区域:语句级。危害:指针被free释放后其地址并不会自动发生改变(非NULL),p成为了“野”指针,这种情况下再对p进行操作,很容易造成程序崩溃,后果非常严重。而代码检查清单正是由若干条这样的缺陷特征描述构成的。3、软件问题报告(SoftwareProblemReport)在软件测试过程中,对于发现的每个软件问题(缺陷),都要进行记录该错误的特征和再现步骤等信息,以便相关人员分析和处理软件问题。为了管理测试发现的软件问题,通常要采用软件问题报告数据库,将每一个