全程软件测试(十五):白盒测试之代码检查常见错误——读书笔记

  数据引用错误

  1.变量在使用前未赋值或初始化

  此错误是较为常见的,在不同环境下都有可能发生。Java、C/C++等语言都要求变量在使用前必须初始化,否则会报错,具体如例1所示。

  例1 Java中未初始化变量错误。

  1  package test;

  2  public class Demo {

  3    public static void main(String[] args){

  4      int sum;

  5      for(int i=1;i <=10; i++){

  6          sum +=i;

  7      }

  8      System.out.println(sum);

  9    }

  10 }

  例1使用Java语言实现1~10相加,但第4行的变量sum没有进行初始化,因此程序不能得到正确结果55,而是直接报错。运行结果如图1所示。

  

  例1运行结果

  2.数组使用时越界

  在数组的使用中,经常会出现数组越界问题,越界问题即超出数组界限。具体如例2所示。

  例2 Java中数组越界错误。

  1  package test;

  2

  3  public class Demo_1 {

  4    public static void main(String[] args){

  5       // 数组大小

  6       int size=5;

  7       // 定义数组

  8       double[] array=new double[size];

  9       array[0]=1.0;

  10      array[1]=1.1;

  11      array[2]=2.2;

  12      array[3]=3.3;

  13      array[4]=4.4;

  14      array[5]=5.5;

  15      System.out.println(array[0]);

  16   }

  17 }

  例2实现给数组每个元素赋值,最后输出数组的第一个元素。数组大小是5,因此包含下标为0~4的五个元素,但第14行对下标为5的数组元素进行赋值,属于数组越界。运行结果如图2所示。

  

  例2运行结果

  3.在数组的引用中,下标不为整数

  不同的语言对数组下标是否为整数有不一样的规定,在有些语言中,数组下标不为整数将导致错误,如C/C++语言。

  4.通过指针引用的内存单元不存在(即虚调用错误)

  当指针的生命周期大于所引用的内存单元生命周期时,错误就会出现。例如,在函数返回局部变量的指针或引用时会产生虚调用错误。

  5.被引用变量或内存的属性与编译器预期不一致

  当C/C++程序将某记录读入内存中并使用一个结构来引用它时,如果记录的物理表示与结构定义有差异,错误就有可能产生。例如,A类型的指针或引用指向非A类型对象。

  6.当通过别名引用内存区域时,内存区域的数据值不具有正确的属性

  EQUIVALENCE语句的使用(在FORTRAN语言中)或REDEFINES语句的使用(在COBOL语言中)都有可能出现此类错误。

  例如,在FORTRAN程序中包含实型变量A和整型变量B,二者均通过EQUIVALENCE 语句而成为同一内存区域的别名。若程序先对变量 A 进行赋值,而后又引用变量B,由于计算机可能将内存中用浮点位表示的实数当作整数,因此可能导致错误产生。

  7.计算位串地址和传递位串参数引发的错误

  在计算机的使用上,当内存分配单元比内存可寻址的范围小时,可能出现直接或间接寻址错误。

  例如,在一些条件下,定长位串不必以字节边界为起点,但地址总是指向字节边界,若程序计算一个位串地址,之后又通过此地址引用此位串,可能出现指向错误的内存位置。将一个位串参数传递给一个子程序时,也可能出现这种错误。

  8.基础的存储属性不正确

  当使用指针或引用变量时,被引用的内存属性与编译器预期可能存在差异,例如,一个指向某数据结构的C++指针被赋值为其他数据结构的地址。

  9.跨过程的结构定义不匹配

  例如,一个数据结构在多个过程或子程序中被引用,每个过程或子程序对该结构的定义可能出现不匹配情况。

  10.索引或下标操作的“仅差一个(off-by-one)”错误

  “仅差一个”错误,又称“大小差一”错误,是一类常见的程序设计错误,具体示例如下:

  int a[5],i;

  for(i=1;i <=5;i++)

  a[i]=0;

  上述示例定义了一个大小为5的数组,并将数组中各元素赋值为0,但循环是从下标为1开始,正确的数组下标是从0开始,因此上述示例会出现“仅差一个”错误。

  11.继承需求未得到满足

  在面向对象语言中,容易出现实现子类没有完全满足父类的继承需求,即继承需求未得到满足的错误。

  数据声明错误

  1.变量未声明

  不是所有语言都需要变量在使用前进行声明,没有明确声明变量不一定是错误,但这可能会导致一些其他问题,因此变量在使用前最好先声明(明确指出变量在使用前不须声明的语言除外)。例如,一个函数的参数需要一个数组传入,但是未将该参数声明为数组类型,这种情况下就可能出现错误。

  2.默认属性不正确

  变量的属性没有明确说明时,即为默认属性,这种情况下程序可能不能正确理解变量的默认属性,这是非常常见的导致意外发生的情况。

  3.变量初始化不正确或与其存储空间的类型不一致

  变量应该按照需求来初始化,不然可能导致错误,如例3所示。

  例3 Python中的变量初始化错误。

  1  lst="suftware test welcome you!"

  2  lst[1]=o

  3  print(lst)

  例3中需要将变量lst初始化为一个列表类型,但实际初始化为一个字符串类型,第2行将lst中第二个字符“u”修改为“o”时程序出现错误,因为字符串类型是不可变的。运行结果如图3所示。

  

  例3运行结果

  4.变量长度和数据类型不正确

  变量的长度问题,通常在数组、列表等含有长度的变量中出现,例如,数组定义的长度比实际所需长度短时,会出现数据无法全部存储的错误。

  5.存在相似名称的变量

  变量名称相似可能会导致混淆,例如,同一字母的大小写、有多重含义的单词等都有可能引发潜在的问题。

  运算错误

  1.存在非算术变量之间的运算

  非算术变量之间的运算如例4所示。

  例4 非算术变量之间的运算。

  1  a="a"

  2  b=2

  3  sum1=a + b

  4  print(sum1)

  例4中第1行的变量 a是字符串类型,变量b是数字类型,因此相加时出现错误。运行结果如图4所示。

  

  例4运行结果

  2.存在混合模式的运算

  混合模式运算,如整型与浮点型运算,具体如例5所示。

  例5 混合模式运算。

  1  package test;

  2

  3  public class Demo_2 {

  4    public static void main(String[] args){

  5          int a=2;

  6          Double b=1.4;

  7          int sum=a + b;

  8          System.out.print(sum);

  9    }

  10 }

  例5是将整型变量 a与浮点型变量 b相加得到的结果赋值给整型变量 sum,运行结果如图5所示。

  

  例5运行结果

  3.存在不同字长变量之间的运算

  相同类型、不同字长的变量进行运算也可能出现错误,如int型和long型。

  4.目标变量字长小于所赋值的数据或结果

  例如,目标变量为 int 型,但赋值给目标变量一个 long 型的数据,这种情况下程序可能报错。

  5.中间结果上溢或下溢

  所谓中间结果上溢或下溢是指在运算过程中出现数据的过大或过小,虽然最终结果可能是有效的,但在运算过程中出现了上溢或下溢情况,可能会导致某些古董数据的精度变化。

  6.存在除以0的情况

  在数学运算中,除数不能为0,这一准则在计算机编程中也同样是铁则。出现除数为0的情况程序直接报错。

  7.操作符的优先顺序不正确

  操作符要根据需求来使用,否则会导致最终结果失败。具体如例6所示。

  例6 操作符顺序编写错误。

  1  #计算2与3的和的6倍是多少?

  2  a=2

  3  b=3

  4  sum1=a + b * 6

  5  print(sum1)

  例6计算2与3的和的6倍是多少。数学中正确的计算方法应该是(2+3)×6,最终结果为30,但第4行代码是先计算了3×6,然后再加上2,操作符运算顺序错误,导致最终结果错误。运行结果如图6所示。

  

  例6运行结果

  从图6中可以看出,所得结果为20,与实际结果30不同。因此,涉及多种操作符运算时,一定要弄清楚需求,明白操作符的优先顺序,并正确使用操作符。

  8.整数除法不正确

  整数除法在不同的语言中可能得到的结果不尽相同。例如,同一个整数除法,可能C/C++中得到的结果与Python中得到结果就不一样。因此需要根据需求的不同来判断整数除法是否正确。

  比较错误

  1.有不同类型数据进行比较

  在计算机比较运算中,不同类型数据之间一般不能进行比较,如日期与数字、字符串与地址等。

  2.有混合模式或不同长度数据的比较运算

  若程序中含有混合模式或不同长度数据之间的比较运算,需要判断编写程序的语言是否能正确理解其中的转换规则。因为有些语言可以直接转换,有些则需要编码人员手动强制转换类型之后再进行比较。

  3.比较运算符不正确

  程序员对需求的理解可能会出现偏差。在中文里,对比较关系的描述有多种,如“至少”“大于”“至多”“不大于”“不小于”“不超过”“小于”“等于”等,其对应的程序中的比较运算符分别是“>=”“>”“<=”“<=”“>=”“<=”“<”“==”。把中文对比较关系的描述转化为程序语言时一定要准确,否则可能缺失有效数据甚至直接报错。

  4.布尔表达式不正确

  程序员在编写关于“与”“或”“非”的表达式时,可能会出现理解失误。而一般这些内容都出现在判断中,因此,布尔表达式的编写错误可能导致整个程序的执行与预期背道而驰。

  5.比较运算符与布尔表达式相混合

  程序中的比较与生活中数学的比较有很大不同。例如,x大于3并且x小于20,在数学中使用比较运算符表示的形式是33)&&(x<20)。编码人员可能会误将比较运算符与布尔表达式混合使用,尤其是初级程序员。

  6.存在浮点数的比较

  计算机是以二进制来存储数据的,数据存储过程中可能存在四舍五入,或使用二进制数来表示十进制数的近似值,因此在大部分编程语言中浮点数是不能进行比较的。

  7.优先顺序不正确

  与操作符一样,布尔运算符也有执行的先后顺序。程序中存在多个布尔运算符时,不仅检查人员可能判断不清各运算符的执行先后顺序,编码人员也有可能将顺序搞混。因此,遇到布尔运算符,需要结合编码语言以及需求说明书来判断整体执行顺序是否正确。

  8.布尔表达式的计算方式不正确

  不同编译器对布尔表达式的计算方式存在差异。例如,有些编译器在做“与”运算时,只要左侧条件为“False”,整个条件判断结果就为“False”;在执行“或”运算时,只要左侧条件为“True”,整个条件判断结果就为“True”。但部分编译器需要两侧均进行运算才能结束判断,因此可能出现错误。例如,if(i==0 || (j/i)> 5)左侧为“True”时,部分编译器直接判断为“True”,但是需两侧均进行运算的编译器则报“除数不能为0”错误。

  控制流程错误

  1.循环最终未能终止

  一般程序中的循环在程序执行完成后都要求能终止(服务器监听循环除外),否则会造成资源耗损甚至计算机崩溃。

  例如,程序中出现while(True)的循环时,循环体进入死循环,最终导致计算机资源消耗殆尽直至崩溃。

  2.存在由于入口条件不满足而从未执行过循环体的情况

  当循环的入口条件不满足时,整个循环体可能一次也不会执行,进而导致整个循环结构没有发挥实质性的作用,实现不了预期结果。具体如例7所示。

  例7 入口条件不满足导致循环体未执行。

  1  #输出列表lst=[2,5,6,8,3,10,4]中所有偶数

  2  lst=[2,5,6,8,3,10,4]

  3  i=0

  4  while(i > len(lst)):

  5    if lst[i] % 2==0:

  6     print(lst[i])

  7    i +=1

  例7是实现输出列表lst中所有偶数,需要对整个列表进行遍历,查找出所有偶数并输出。其中第4行的循环入口条件应该是“i < len(lst)”,即当i小于列表lst的长度时进入循环,但例7中写成了“i > len(lst)”,而i的初始值是0,因此循环不会执行,预期结果也不可能实现。例7运行结果如图7所示。

  

  例7运行结果

  从图7中可看出程序成功执行,但最终结果并不是期望的结果。

  3.存在“仅差一个”的循环错误

  此类错误一般出现在迭代数量判断中,最终结果输出了,但结果可能并不是所预期的结果,正好迭代少一次或多一次,具体如例8所示。

  例8 “仅差一个”错误。

  1  #输出列表lst=[2,5,6,8,3,10,4]中所有偶数

  2  lst=[2,5,6,8,3,10,4]

  3  i=1

  4  while(i < len(lst)):

  5    if lst[i] % 2==0:

  6     print(lst[i])

  7    i +=1

  例8与例7目的相同,都是输出lst中所有偶数。整个程序运行并不报错,但可以发现循环是从下标为1开始的,而列表的下标是从0开始的,因此会导致少执行一次,执行结果如图8所示。

  

  例8运行结果

  从图8中可以发现,上述程序输出结果为6、8、10、4,原列表中第一个元素2也是偶数,但是最终结果并没有输出,原因在于循环少了第一次,即“仅差一个”错误。

  4.程序结构中的括号以及固定搭配不匹配

  程序结构中的括号(( )、[ ]、{ })都是成对出现的,缺少任何一半程序都会报错;程序中很多结构需要搭配合理才能实现预期效果,例如,需检查 if…else…每一层搭配是否合理, do…while…有没有缺少某部分等。

  5.多分支路径中,索引变量大于可能的分支数

  当循环采用多分支时,需要考虑实际出现的情况数量是否会大于总分支数量,一旦大于,未被捕捉到的情况对整体的程序会不会有影响等。因此,尽量保证采用的分支包含所有程序执行可能遇到的情况。

  6.程序、模块或子程序最后未终止

  进行代码检查时需要确认整个程序中的每一个模块或子程序在执行完成后都能终止。

  7.存在不能穷尽的判断

  选择结构中的判断情况一定是可穷尽的。

  例如,程序期望输入值为1、2、3,当输入值不为1、2时一定要是3,即输入情况只能是1、2、3这三种情况,否则程序的执行结果不一定是预期结果。

  接口错误

  1.形参与实参数量不相等

  例如,函数定义的形参数量是3个(无默认参数),但函数调用时只传递了两个实参,导致整个函数无法执行,最终也得不到预期的返回值。因此要确保函数(无默认参数)定义与调用时,函数的形参和实参数量相等。

  2.形参顺序与实参顺序不匹配

  对于接口,调用时传递的实参顺序就是定义接口时的形参顺序,因此编码人员在调用接口时一定要确保传递的参数顺序与接口定义的形参一致,否则即使程序能正确执行,接口所返回的结果也是错误的。

  3.形参属性与实参属性不匹配

  在调用接口时须注意传递的参数属性要与接口定义时定义的形参属性一致。例如,当接口需要传递一个整数,而传递的参数是一个字符串,执行时就会发生错误。因此形参与实参的属性要相匹配。

  4.形参的单位和实参不匹配

  例如,接口是计算某长方体的体积,需要传入长方体的长、宽、高(单位:cm),最终进行计算,返回的体积单位是 cm3。编码人员在调用接口时传递的是长、宽、高(单位:m)三个参数,虽然属性、顺序都匹配,但是最终得出的体积单位应是m3,因此达不到预期结果。

  5.改变了某个仅为输入值的形参

  有些数据是不能在子程序中进行修改的,例如,C++中const关键字声明的常量是不能被子程序修改的,修改则报错。

  6.全局变量的定义和属性不一致

  同一全局变量在程序的任何地方使用都需要定义和属性一致,否则程序报错。

  7.某模块或类含有多个入口点,却引用了与当前入口点无关的形参

  不同的入口点有不同的形参,因此需要传递不同的实参,在入口点引用其他入口点的形参会导致错误。

  8.常数以实参形式传递过

  在一些编程语言中,常数以实参形式传递是致命错误,如FORTRAN语言。

  输入/输出错误

  1.文件属性不正确

  若文件已声明,则需要确保文件属性均正确。

  2.打开文件的语句不正确

  判断所编写的打开文件语句是否正确,并且检查语句中其他属性的设置是否正确。例如,需求应以只读形式打开,代码中不能出现只读形式以外的其他设置。

  3.格式规范与I/O语句中的信息不吻合

  例如,FORTRAN语言中,每个FORMAT语句都需要与相应的READ或WRITE语句信息吻合,否则可能导致错误。

  4.缓冲区、内存大小不够保留程序将要读取的文件

  需要读取文件时,要确保缓冲区、内存能够保留读取出来的文件数据。若缓冲区或内存空间明显不足,则直接报错。

  5.文件在使用前未打开

  文件在使用前都须确保已经打开,否则程序报错。

  6.文件在使用后未关闭

  文件使用完后必须对文件进行关闭,否则文件后续可能会遭到影响或破坏。

  7.文件结束条件未正确处理

  在文件使用完时需要再次判断文件的结束条件,并且正确处理。

  8.未处理I/O错误

  在输入输出出现错误时,确认处理方式是否正确可取。

  9.打印或输出的文本信息中存在拼写或语法错误

  对最终输出的内容进行检查,确保输出的内容没有拼写或者语法方面的错误。

  其他检查

  1.存在未引用过的变量

  在程序中存在未引用过的变量需要进行处理。因为变量在声明时系统会为其开辟内存,占用资源。

  2.变量的属性和赋予的默认值不一致

  检查整个程序中的变量属性以及所赋予的默认值是否满足需求,并且是否前后一致,防止出现错误。

  3.编译通过的程序存在“警告”或“提示”信息

  对于编译通过的程序,需要检查是否还存在“警告”或“提示”信息。它们虽然目前在程序运行过程中不会产生影响,但不能确保在以后的开发中不会引发错误,因此应尽量避免类似信息的出现。

  4.程序或模块未对输入的合法性进行检查

  用户的输入永远是不可靠的,因此需要程序来对用户输入内容的合法性进行检测,禁止非法内容进入程序。这也有利于保证软件的安全性。

  5.程序遗漏了某个功能

  在整个程序完成之后,需要小组成员将需求报告与已完成的程序进行对照,确保每个功能都得到实现。尤其是在实现功能比较多的项目中,更容易出现功能遗漏的情况。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值