什么是好的测试用例(二)

上一篇 / 下一篇  2009-01-18 21:53:39 / 个人分类:测试用例

测试在于暴露缺陷把我们关注的焦点局限在测试团队的两个主要目的上:

  除了开发团队意外的人,会考虑寻找有关的(值得报告的)缺陷并修改这些缺陷。

  即使在这些目的范围内,也有很多种不同的好的测试方法。例如,我们也许会说一个测试好于另一个测试,如果它:

  更有力。

  根据一般的统计学常识,我是这样理解有利的:如果存在缺陷就更可能暴露出来。注意,对一类缺陷来说,测试1比测试2更有力;对另一类缺陷来说,测试1不如测试2有力。

  更可能产生重大(更有根据、更有说服力的结果)。

  如果对一个重大问题有影响力的负责人拒绝修改这个问题。(负责人是指对产品有影响的人。对产品有影响力的负责人是指其喜好和观点会导致产品变更的人。)更可靠。

  可靠的测试更可能像是程序员或其他有影响力的负责人进行的真实的(或合理的)操作集合。“边角测试”是程序员惯用的一个例子,它是说测试或缺陷不可靠:“没有什么可以证明它。”如果有些(或所有)对产品有影响力的负责人同意测试用例的真实性,那么它就是可靠性。

  更可能发现客户遇到的典型事件。

  设计的很多测试都有很高的可信度。让你的人去影响真正的使用用途。

  越经常出现的活动组就越可能被覆盖或完全覆盖。(我说的活动组是指很多特性同时被用,所以我们就追踪哪些特性集合体按照什么次序被使用了,并根据我们的分析反映这些信息。)更详细的请参阅Musa的(1998)关于软件可靠性工程。

  更易于评价。

  问题是程序是否通过了测试?为了易于进行评价,测试人员应该有能力快速、不费力地决定程序是否能通过测试。说程序可能是否会测试是不够的。较难进行评价的是,花费的时间越多,错误越可能在不经意间闪过。面对费时的评估,测试人员会用便捷的方法、另辟蹊径来减少程序是否完好的费时的评测。这些便捷的方法往往不完全精确(就是说,他们会发现不了明显的缺陷或把正确的代码标记为错误的。)更有利于解决问题。

  比如,在不能给有关测试条件提供大量信息以重现问题的情况下,大量的自动测试经常会搞毁系统。

  他们对解决问题没有好处。越难重复的测试越不利于解决问题。

  如果需要解决的问题是由这个测试发现的,那么这个测试就越难执行,下次测试也越难执行正确。

  更有信息量。

  测试的价值就是我们能从中学到东西。

  大多数情况下,你从通过测试的程序中学到的东西比没通过测试的程序中学到的多,但有信息的测试会教你(减少不确定性)判定程序是否能通过测试。

  比如,如果我们已经在多次构建之后运行了一个测试,并且程序每次都可靠地通过测试,那么我们就期望程序能再次通过这项测试。从重复测试中得到的另外的“通过”结果不会有助于我们对程序的认知。

  等价类的观点是信息价值的另一个例子。任何测试背后都是一个测试集,他们之间有很高的相似度,我们认为其他测试实质上是这个测试的冗余。用口头的行话说,这就是“等价类”或者“等价部分”。如果这些测试充分的相似,那么第二次测试得到的附加信息会少于第一次测试。

  这个标准很接近于Karl Popper的实验价值理论(参考Popper 1992)。优秀的实验涵盖了风险预测。这个理论预言人们期望的某些事物并不真实,你偏爱的理论是错的或者会令许多人感到惊讶。Popper分析认为优秀的实验(优秀的测试)是近似于科学哲理的主流核心理念。

  或许,在这里真正要考虑的是,你希望从测试中学到的东西与测试设计、运行的机会成本是均衡的。你花费在测试上的时间就是你没有花费在其他测试或活动上的时间。

  更加复杂。

  一个复杂的测试包含被测软件的很多方面、或变量、或其他属性。

  当程序有很多变更或一次测了很多特性时,不提倡用复杂测试。如果程序存在很多BUG,复杂测试很快就会失败,也就没必要再执行它了。测试组主要依靠复杂测试发现模块化的BUG。模块化的BUG使很多测试都无法通过,阻碍测试组了解测试应该暴露的信息。因此,测试初期,进行简单测试是合理的、有必要的。当程序更稳定时,或(在极限编程或任何开发生命周期)程序有了更稳定的特性时,更复杂的测试就会变得更有意义。

  更可能帮助测试人员或编码人员洞察产品、客户或者外界环境的某些方面。

  有时,我们通过测试了解产品,了解其如何运转以及存在的风险。随后,我们会设计测试来暴露产品的缺陷,但测试刚开始时,我们会对“是什么”和“怎么测”感兴趣。很多这样的测试不会重复进行。然而,在第一次测试环境中,期望(典型地,单元)测试集合警示编码人员实验上出现代码变更的副作用。在这种环境下,设计的测试会标记出性能变更、化整误差的差异、或者其他某些变更,这些都不是缺陷。程序中意想不到的变更会警示编码人员,她的代码或代码变更影响的原型是不完整或错误的,并引导她进行额外的测试或者解决问题。(感谢Ward Oummingham和Brain Marick提供的这个例子。)测试类型和测试质量在黑盒测试的领域中,Kanner&Bach(参考Bach 2003b和Kanner,2002发布在www.testingeducation.org上的课程笔记,以及Kanner,Bach & Pettichord, 2002)描述了11种有优势的黑盒测试:

  ●功能测试●域测试●基于规范的测试●基于风险的测试●压力测试●回归测试●用户测试●场景测试●基于状态模型的测试●大批量的自动测试●探索性测试我和Bach收集了一些测试“范例”进行反复领会,其中的一两个统治了测试组团队或天才测试者的思想。经过分析,我们发现有趣的是:

  如果我是一个“场景测试者”(主要根据场景测试的应用定义测试的人),我该如何实际地测这个程序?什么能使场景测试一个比一个好?我会遗漏哪类问题,对我来说难于发现或解释什么,什么又特别简单?

  在这里,用一些怎样的测试用例才算是“好的”的思想,来简单的说明一下这些类型。

  功能测试独立测试每个功能、性能、变量。

  很多测试团队都从非常简单的功能测试开始,再转换到另外一个,通常有若干功能之间的互相交叉,直到程序通过主要功能的测试。

  依照这种方法,好的测试应聚焦于单一的功能,并用中庸的值来测它。我们不希望程序败于这样的测试,但还是会败于有根本性错误的算法、失败构建、或对程序其他部分有牵制力的变更。

  这些测试具有很高的可靠性,并易于评价,但明显没有力度。

  有些测试团队会把大多数时间花费在功能测试上。对他们来说,当每一项都独立彻底地测试过时,测试就完成了。依我的经验,有力度的功能测试类似于域测试,有他们的实力。

  域测试这种测试的本质是取样。我们把集合划分(区分)成子集合(子域),把一个大的可能进行测试的集合分解成一个小组,并从子集合中选出有代表性的一两个的方法。

  在域测试中,我们关注变量、偶尔是变量的初始值。

  为了测一个给定的变量,测试集把所有你能想象到的值(包括无效值)都赋给这个变量。把这个集合划分成子域,在每个子域中至少进行一个典型测试。一般地,你进行了一个最具代表性的测试,也就是说,你用了一个至少像同类其他元素一样可能暴露错误的值。如果这个变量能达到数据边界,那么最具代表性的就是典型的边界值。

  大多数域测试的讨论都是关于输入变量值能否达到数据边界线的讨论。这些用例区间中最具代表性的是典型的边界用例。

  对于数字变量,一个好的域测试用例集合会检测每个边界值,包括最小值、最大值、一个小于最小值的值、以及一个大于最大值的值。

  Whittaker(2003)提出了一个在软件分析时关于许多不同类型变量的深入讨论,包括输入变量、输出变量、中间计算结果、文件系统中存储的值、以及发送到设备或其他程序的数据。

  Kaner,Falk & Nguyen(1993)提出了关于变量(配置测试打印机类型)不能达到数据边界的测试的详细分析。

  这些测试比不具代表性的或忽略某些子域(比如,人们经常忽视期望产生错误信息的测试用例)的测试更有力。

  第一次运行这些测试用例,或重大相关变更之后,这些测试会产生很多有价值的信息,因为边界/极限值错误是普遍发生的。

  有时,会忽视这些测试发现的BUG,尤其是当你同时测试若干变量的极限值时。(这些测试叫做拐角用例。)他们不需要是可靠的,不需要代表用户期望的,因此,他们也没必要是为解决问题而设的。


TAG:

 

评分:0

我来说两句

Open Toolbar