前几天我在微博上发出了一个STB-010(
软件测试在线公益课程系列)报名通知的帖子,这一讲的题目是“软件测试黒盒技术与应用 - 状态转换测试方法”,立即引来了一些讨论。
比如朱少民老师就指出:“人们喜欢将软件测试分为白盒、黑盒方法,虽然方法论上是成立的,从完全不同的方式去看待SUT,有其不同的应用场景,但是这种划分越来越感觉不合适,如将等价类划分、边界值分析...等归为黑盒方法,而它们完全可在代码测试上*透明*应用,如针对参数传递、内部变量等进行测试,是时候重新审视测试方法体系了。”
我个人对上述观点总体上是表示认同的。不过细微之处还可以深究下。
比如,“将等价类划分、边界值分析等归为
黑盒测试技术”与“它们完全可在代码测试上*透明*应用”,我并不认为这二者前后矛盾!“黑盒”是一种思想,将当前正在考虑的问题看作一个黑匣子,忽略其内部实现的细节,从外部考虑其行为表现。换句话说,此时我们正站在更高一级别的抽象层次上看待问题。
这个黑匣子可能很大,比如是整个被测系统;它也可以很小,比如对应到一个函数。因此,我们可以将各种黑盒
测试技术应用到整个系统层面,也可以在代码层面应用他们。实际上,“等价类划分、边界值分析”等只是一些测试技术,如何使用这些测试技术,完全取决于上下文,这个观点也是“上下文驱动测试学派(Context-Driven Testing School)”所倡导的。
有不少人仍然认为“只要在代码层面做测试,一定指的就是
白盒测试”。我们首先来看看一些白盒测试的定义。
ISTQB定义White-box Testing为“Testing based on an analysis of the internal structure of the component or system.”该定义认为,不论是在
单元测试阶段还是
系统测试阶段,只要关注的是被测对象内部的结构,就归为白盒测试。比如关心某段代码的各种测试覆盖情况(分支覆盖、条件覆盖等),属于白盒测试的范畴,这点相信大多数人能够理解。但是另外一些情况也许就不那么容易理解了,比如在GUI测试中,测试人员检查菜单调用的是否正确(主菜单和各层子菜单的嵌套调用情况),而不关心每个菜单内容的正确性与否时,就是在做白盒测试了。
我个人觉得这样理解白盒测试有些牵强。菜单的调用结构是否正确,也不妨认为是系统
功能测试的一部分,此时也是把系统当做黑盒来测试的。如果测试人员通过阅读分析代码来判断这种菜单调用的具体实现是否正确时,这倒可以归为白盒测试。当然,不论黑盒、白盒,只是个概念而已,重要的是想清楚在什么时候应该做什么样的测试,应该完成哪些具体的测试活动。
再回到前面的问题,“只要在代码层面做测试,一定指的就是白盒测试”吗?答案是否定的。原因有二:如果是通过阅读代码来了解SUT,那么代码只是一种
学习的手段,就像有时需要通过阅读文档来了解被测系统一样,看过代码之后自然可以做黑盒测试;对于任何一个函数或者类,如果把它作为一个黑匣子,考虑它实现的主要功能时,使用等价类或边界值等测试技术对它进行分析,那么我们自然是在做黑盒测试。
可见,是做黑盒还是白盒测试,与是否阅读代码没有直接的关系。假如黑盒测试是把被测对象当作一个黑匣子来看,那么白盒测试就是打开这个黑匣子,深入内部挖掘细节的测试过程。当然,由于代码内部包含很多实现细节,基于代码做测试的时候,往往比纯粹的基于需求文档做测试想到更多的测试点,也有人把这称为介于黑盒与白盒之间的所谓灰盒测试。
“黑盒”与“白盒”的抽象层次
既然“黑盒”与“白盒”分属于不同的抽象层次,而抽象又是分很多层的,那么当我们讨论某测试是黑盒还是白盒时,就离不开具体的测试上下文了,因为所谓的“黑盒”与“白盒”是相对而言的。这就像当我们讨论“集成测试”时,此“集成测试”非彼“集成测试”,一个系统中从单元、模块、子系统、系统等各个层次的接口很多,讨论的双方一定要先明确是在哪个层次上讨论“集成测试”的问题,这样讨论的结果才有意义。
“黑盒”与“白盒”分属于不同的抽象层次上,测试人员应该更多关注黑盒测试,还是更多关注白盒测试,或者二者都应给予足够的关注?
朱老师的另外一个帖子:“当系统复杂时有必要简化问题,减少内部干扰,把系统看作一个整体(黑盒),搞清楚系统边界、接口、环境。只有此时(宏观层面上)黑盒方法是有意义的。而我们不能认识系统、无法理解系统/业务结构的时代可以过去了,我们应能够彻底搞清楚代码、数据、业务及其结构、控制流等,软件测试才是有效、充分的。”
如果这段话中的“我们”泛指的是“测试团队”,我深表认同。对于每一个测试人员是否也要黑盒白盒通吃,可能要根据具体的测试上下文(产品和项目复杂度、人员技能水平等)来确定了,这属于一个测试项目具体的测试策略的问题。但是这并不妨碍每个测试人员把掌握黑盒与白盒测试技术作为自己努力的目标和方向。
为什么说“同时做好黑盒与白盒测试,软件测试才是有效、充分的呢?”举个例子来说明。
有这样一段代码,输出0~99共100位数字:
int x;
for(x=0; x<100; x++);
cout<<x;
结果由于程序员粗心,多加了一个分号,导致实际输出的只是100而已。这种错误是比较常见的,如果把这一小段代码呈现在我们面前,我们用代码review的方式很容易就能找出这个bug。但是现在试想一下,把这段代码放到一个有几百万行代码甚至更大的一个系统中,通过代码review找出这个bug,无异于大海捞针!
况且,增加一个多余的分号并没有违反什么语法规则,编译器也只是会认为这是一个循环体为空的循环语句而已,并不会有错误提示。
您可能会说,这简单,用黑盒测试的方法运行一遍基本功能,很容易就发现了。但是,谁又能保证黑盒测试可以覆盖所有的bug呢?毕竟,测试是无穷无尽的,永远也执行不完,而漏测是必然的。
可见,单单用白盒或者黑盒的方法都不是绝对保险的,并且黑盒测试和白盒测试由于他们的视角不一样、所处的抽象层次不一样,能够发现的缺陷类型、发现缺陷的难易程度、发现缺陷的成本多少、对测试人员的技能要求等都不一样,有效地将二者结合起来使用、互为补充,才能使测试效果最优。
结论
不必太在意“黑盒测试”与“白盒测试”具体的定义,他们只是辅助我们做好实际测试工作的一些概念而已(您甚至可以有自己的一套定义、一套术语);
“黑盒”与“白盒”体现的是测试人员思考问题的一种方式,“黑盒”将被测对象当作一个黑匣子,考虑其整体表现;“白盒”将一个个黑匣子打开,深入内部探索细节。
大体上,“黑盒测试”与“白盒测试”分属于不同的抽象层次,黑盒更偏重于概括一些,白盒更偏重于具体一些;
“黑盒”与“白盒”的抽象层次是相对的,一个系统可能有多层的抽象;
“黑盒测试”与“白盒测试”二者结合起来使用,互为补充,测试才更充分。