1.想不想测试软件?
局部性测试的重点把测试经验、专业知识、软件在操作环境下如何构建和运行的知识结合在一起,是我们在测试中做出正确决定。
决策分为5部分:
a.输入(input)
b.状态(state)
c.代码路径(code path)
d.用户数据(user data)
e.执行环境(execution environment)
2.测试就是有所变,有所不变
测试人员进行测试时必须回答如下问题:
a.软件运行时的表现是否符合设计预期?
b.用户为了某个功能而购买了软件,可是软件是否实现了这个功能呢?
c.软件运行时,是否足够快、足够安全、足够稳定呢?
我们必须在测试时确定所有可能发生变化的因素,在要求我们选择某些变量和去掉其他(也就是不必要的)变量时,我们必须做出明智的决定。
这把测试工作简化为先在所有输入(或运行环境等)的全体集合中选择一个子集,然后在输入时使用选择的子集,最后通过推理认定是否这些输入已经足够多了。
3.用户输入
(1)用户输入的基本知识
输入是由应用程序外部引发的,并导致应用程序执行某些代码。
输入大致分为以下两类:
a.原子输入(atomic input)
b.抽象输入(abstract input)
(2)如何测试用户输入
所有的软件都会执行四个基本任务:
a.接收输入
b.产出输出
c.存储数据
d.进行运算
(3)合法输入和非法输入
正向测试(postive testing):想确认程序可以进行正常工作
逆向测试(negative testing):想办法让它失效
对于开发人员认为的非法输入值,他们通常会实现一段错误处理(error-handling)代码,用于处理这些情况。他们在哪里编写了错误处理代码,具体代码是如何实现的,这些都需要测试。
开发人员有三种基本方法来定义错误处理程序(error handle):
a.输入筛选器(input filter)
b.输入检查(input check)
c.使用异常(exception)
(4)输入筛选器
输入筛选器用于防止非法的输入值被传递给应用软件的功能代码。
输入筛选器不会产生错误信息(这是它和输入检查的区别所在),相反,输入屏蔽器默默地把非法输入值排除在外,只把合法的输入值传给应用程序。
比如,一个图形界面的应用程序有一个面板可以接收整数值,该面板可以忽略所有的字符或字母输入值,只显示键入的数值输入值。
还有,所谓的列表框和下拉列表框是一种输入筛选器,因为它们只提供那些合法的输入选项。
从测试的角度,对于输入筛选器,我们需要检查如下几个方面:
a.开发人员是否正确的实现了该功能?比如,把一个非法输入值归于合法的输入范围,就会导致改非法值突破软件的唯一保护层。与此相对的,把一个合法的输入值归于非法的范围,可能会导致软件拒绝服务(denial of service)和严重的用户不满。
b.是否可以绕过屏蔽器?如果有某种方法可以让输入值进入系统,或者当输入值进入系统后还可以被修改,那么该屏蔽器就没有什么用处,开发人员还必须实现更多的错误检查代码。
(5)输入检查
输入检查属于应用程序代码主线的一部分,通常通过类似if、then、else结构的语句来实现(或者是case、select结构,或者是查找表lookup table的方式,这和具体使用的编程语言相关)。它们会接受一个输入值,如果输入值合法,那么接着运行处理它,否则就产生一条错误消息并中止处理。实现了输入检查后会报警,通常就是显示一条错误信息,该信息会描述当前状况,并准确的表示当前的输入值出现了不合法的情况。
测试人员必须牢牢抓住显示的错误信息,建议必须仔细阅读每一条错误信息。错误信息一般会指出当前输入值被认定为非法制的根本原因以及如何修改让它变成合法输入值。这可以给我们很多启发,比如还有哪些输入值可以触发其它一些错误信息,或者哪些输入值实际上应该导致错误出现而软件却没有报错。
输入检查和异常处理的根本差别在于代码的位置,当程序从外部接收到输入值后,一般紧接着就是输入检查代码。读入输入值的代码之后会紧接着跟着一个if语句,用户检查输入值是否合法。所以显示出的错误信息会非常准确,如“不允许输入负数”,它告诉用户当前输入值哪里出了问题。如果信息比较笼统,往往表示这里使用的是异常处理的方式。
(6)异常处理代码
异常处理代码把整个例程(routine)当成一个整体看待,检测骑其上发生的任何一个错误。
(7)常规输入还是非常规输入?
a.常规输入:开发人员计划中的输入,也是真实用户常使用的输入值。
b.非常规输入:只在那些比较特殊的情况下才会发生。
(8)默认输入或用户提供的输入?
a.默认输入:在空白字段中不输入字符或是给某个API传递一个NULL参数或是开发人员设置的默认值,它们都需要软件在默认(default)的情况下运行下去。
b.用户提供的输入
(9)使用输出来指导输入选择
从抽象的角度而言,最高层次的抽象是把输出分为非法输出(illegal output)和合法输出(leagal input)。
测试方式:
a.测试人员首先确定他们希望程序产生什么样的输出结果,然后考察所有的用户场景,看看如何去生成期望的结果。
b.先观察输出结果,然后再选择新的输入,并保证新的输入是重新计算后的结果,或者是确保新的输出结果和原先不同。
c.寻找那些被保存起来的输出结果。
4.状态
(1)软件状态的基本知识
输入导致内部变量的数值发生变化,内部变量所有可能的取值组成了软件的状态空间(state space)。
软件的一个状态就是状态空间中的一个点,它由所有内部数据结构的取值来唯一确定。
(2)如何测试软件状态
软件状态可以看成是用于描述软件记住过去发生的所有输入和输出的一种方式。
a.状态可以是临时的(temporary),就是说它在当前运行中会被程序记住,但当程序终止时,该状态就被忘却了。
b.它也可以长期保存(persistent),他可以被存储在一个数据库里或一个文件内,程序将来再运行时可以存取这个值。
这两种情况一般被称为数据辖域(scope of data),检查软件是否正确实现了数据辖域也是一项很重要的测试。(如果数据辖域有问题,很可能导致安全隐患。)
5.代码路径
一条代码路径(code path)就是一连串的代码语句,它起始于软件开始运行的语句,中止于一条特定的语句,往往就是那条代表软件运行结束的语句。
测试人员必须明确知道程序里可能有哪些分支,并理解哪些输入会导致软件走这条分支而不是另一条。
分支语句仅仅是导致代码路径增加的各种语句中的一种。循环语句可以导致代码路径的总数变成无穷大。
6.用户数据
创建一个含有特定数据的数据存储,它含有的数据应该和软件真实用户的数据尽量相似。
7.运行环境