在预算上需要注意的地方
我想让你尽可能的准确估计在你的自动化测试中平均会出现的bug数是多少,并将结果告诉我。你的答案不应该是“0.25”或是“0.25±0.024”。你的答案应该象这样“我会努力减少bug数的出现”或者“我的bug决不会再次出现”。
稍后,你会被要求估计一个测试的生命周期(生存时间)。这个答案应该是这个样子的:"不会超过软件的发布时间" 或者 "a long time" than "34.6 weeks".
然后,你会被要求估计在测试生命周期内可以找到多少个bug?答案依然是模糊的。
最后,你会被要求对自动化测试和手工测试模糊估计的结果做一个比较并做一个结论。
这样做有用吗?
回答是肯定的。当你考虑选择谁的时候,需要做出这样的比较——也许不是在表面上做的——尽管是一些少的比较模糊的数据。我的经验是快速的回答这些问题希望可以引导一次优秀的测试,不去管答案是否精确。我在这里倾向于不需要精确的去回答这些问题,但是有用的问题和容易被误解的问题必须要做精确的回答,不要给别人带来误导。
How Long Do Automated Tests Survive?(一次自动化测试的生命期会有多久?)
当代码做了改动之后,自动化测试显示出它的价值所在。除了一些极少数类型的测试以外,在代码未作任何改动之前去做重复测试是一个浪费时间而且没有任何效果的做法:它会找出一些bug,但和你第一次做测试所发现的是一样的。(例外,像所用时间测试和压力测试可以概略的用同一中方式来分析。因为简单我忽略了它们。(I omit them for simplicity.))
但是一个测试不会永远的持续下去。一些观点指出,产品上所做的变动很可能破坏一个测试。这个被破坏的测试将不得不做出修改或是被丢弃。我有一个很合理的近似值是这样的,我们去做一个测试的修改和抛弃已有的测试而重新编写一个新的测试的价值是同样的(注释3)。但是无论在变化后你做什么补救,如果修改和重新编写都不能达到要求的话,我认为放弃它而使用手工测试会比较好一些。
简而言之,测试的有用寿命看起来像是这一样:
________________________________________________________________________________________
(注释3:如果你使用录制工具能够将一次测试重放,那样的价值将会比在开始测试时记录其预期结果要有价值的多。花一些时间和精力在这个上面是在一次测试中是很有必要的。如果你要修改测试脚本,你需要正确地理解这个脚本,修改它测试它,确定你没有可能揭露的所有问题。你会发现新的测试脚本不可能完成老脚本能做的所有功能,所以可以将一个修改测试保留新旧两个测试脚本。如果你的testing effort已经确定下来,那么去修改一个测试要比从头开始写一个测试要好的多。这些将会不影响你在纸上做的工作;那样做会减少自动化测试所需要的花费。这一切的前提是你要清楚的认识和把握一次修复所需要的代价,人们往往会把代价估计不足。)作者: pcl2004_27 时间: 2004-6-27 11:01
假设你的工作是要写一组测试来检测用户是否输入了正确的电话号码,那么你就需要检查是否是输入了有效地阿拉伯数字而非其它字符等等。如果你清楚其中的代码(据我了解很少人会这样)你可以设计一个规划列表将校验电话号码的代码使用高亮显示做出标记。通常称它为 the code under test。这部分代码可以更加完善你的测试任务。
在大多数时候,你不可能有机会直接运用the code under test。例如:你不可能直接得到确认电话号码的那部分代码,因为它通常会是一个用户的一部分属性,就需要通过用户接口来测试,将与其关联的那部分代码组织起来,使这部分转变到内部程序的数据,并会按照常规将这部分数据表现出来。当然,你也不能直接对表现出来的数据进行检测,因为转变会通过其他的代码来将其转变成在用户界面可见的最后的数据(就像非法的数据会转换成错误信息)。我称这些代码为intervening code——介于测试本身和code under test之间的代码。
Changes to the intervening code(对介入其间的代码进行变化)
介入其间的代码是导致测试死亡的主要因素。而且用户图形界面接口较上文提到的那个接口和一些硬件驱动接口相比更是这个样子。例如:假设用户接口要求你输入电话号码,但是现在变化为要求提供一个电话按键区的视觉表现。这时你要使用鼠标敲击号码模拟使用真实的电话。(这是个非常愚蠢的主意,但是这怪异的事情已经发生了。)尽管接口传给了code under test一个正确的值,但是用户界面的变化很可能破坏一次自动化测试,是因为很可能使用者再没有地方输入电话号码了。
就像另外的一个例子,一个输入的错误用户界面会用其它的方法来告诉用户。它可能会刷新主窗体使其显示红色同时发出特殊的声音来代替弹出的提示信息来告知你不能完成这次操作。但是,如果你的测试是通过测试是不是弹出提示信息来判定的,那么将视这种正常的运行为一个bug。很显然这个测试就没有效果了。
"Off the shelf "测试自动化工具能做避免测试死亡的有限制的工作。例如:大多数的GUI自动化测试工具都可以忽视文本框大小、位置和颜色的改变。从而把握像上面两段所提到的那些大的改变,但是需要事先定制。这需要在你的工程中有一些人去创建test libraries。这样就要求你,一个测试人员,在编写好测试的特殊术语,尽可能多的忽略用户接口的细节。例如,你的自动化测试可能包含这样一行定制的信息:try 217-555-1212 try是test library程序,它的作用是将电话号码翻译成接口可以知道的术语。如果用户界面接受在输入框中输入字符,try会在其中输入电话号码。如果需要通过显示在屏幕上的特定图形区域键入电话号码时,try也会做到。
test library 可以有效地将那些不相关信息过滤掉。这样我们就可以详细的准确的测试那些与功能相关的数据。在输入上,增加这些附加信息是intervening code所必须的。在输出上,它们将intervening code中的信息全部压缩到一个很重要的模块中,其中的信息实际上可以当作是Code Under Test的一个延伸。这种过滤可以用左图来描述:
多数用户界面的变化不会需要对测试做更改,而只需要对test library做相应的修改。应为test Code要比library Code多的多,所以只修改library Code的代价会很低。
但是,尽管我们有更好的补偿性的代码也不可能将测试从所有的变化中隔离出来。它仅仅是尽可能的去预期所有的事情。所以其中有很多可能性,将来很可能出现一些问题破坏你的测试。你必须问自己这样一个问题:
在变化中Intervening Code会把测试保护到什么程度?
你需要估计intervening Code的改变对测试造成影响的可能性。要保证用户界面永远的不会改变是一件不可能的事情,这就使你需要不停的改变自动化测试的脚本以保证测试可以自动的执行。(我不会相信界面冻结后永远不会变化,除非manager答应如果以后每做一个新的修改将会给我100美元)
如果变化是可能的,你一定会被询问对你的test Library保护你的测试不受其影响正常执行有多大的信心。如果说test Library不能保护测试,那么起码它可以很容易的做出改动以适应变化。如果花费一个半小时的时间可以拯救300个测试,那么所做的一切是值得的。但是,小心:很多人往往低估了维护test Library的困难,特别是在变化后需要手工的对测试test Library进行反复的修改。不应该马上就放弃,抛弃所有的测试类和test Library,从头开始,因为很可能只需要简单的修改就可以完成需要的测试。
如果你没有test Library——如果你正在使用自动化GUI测试工具来捕获和重放模式——你不要期待会有任何保护。一次对界面的修改会让你的大部分的测试“死亡”。往往不会有足够的时间来允许我们完成对发生变化的测试进行修改,我们不得不在少的花费和短的生命生存期之间做出选择。作者: pcl2004_27 时间: 2004-6-27 11:02
Changes to the code under test(改变测试下的代码)
Intervening Code不是唯一可以变化的代码,code under test同样可以变化。特别的是,它可以改变使其完全不同的去做某件事。
例如,假设几年前某个人写了一个关于点话号码的校验测试,为了检查那些不符合要求的电话号码,就像1-888-343-3533。在当时,没有888这样的电话号码,但是现在却存在这样的号码。这样就导致了测试拒绝888号码给出提示,尽管现在这个号码是合法的,但是测试脚本会按照先前的规则进行测试从而拒绝它。解决这件事情可能很简单也可能很复杂。如果你了解问题所在那么这件事是一件很容易的事情:只需要将“888”改为“889”。但是可能很困难对测试做足够的解释去了解测试电话号码整个的方法。或者你没有意识到“888”再现在来说是一个合法的号码,所以你会认为测试理所应当的测出这条Bug。测试在你使用一些假的“Bug”来骚扰开发人员之前是不会固定不变的。
所以,在决定是否要进行自动化测试之前你同样需要问自己这样的几个问题:
code under test 行为的稳定行如何?
注意强调的“稳定性”——只要他们保持外部可试行为相同代码的代码就OK!
不同类型的产品,不同类型的code under test有不同的稳定性。电话号码实际上还是相当稳定的。再如一个银行帐目管理系统可以说是一个相当稳定的系统,如果每次存100元需要收取30元的手续费那么记录到帐的就是130元,这种关系是稳定的(除非银行改变了收费的标准)。而用户的界界面是相当的不稳定的一个因素。
增加行为往往是无害的。例如,可能有这样一个检查,测试从一个帐户撤回 $100 由于 $30 生产错误导致操作失败但是帐户余款方面的没有改变。但是,现在测试被重写,增加了一个新的特性:顾客可以根据需要确定是否需要“自动透支保护”功能,它允许用户提取多余他帐户内存在的钱数。这种变化不会破坏现有的测试,只要默认的帐户测试保持原来的行为。(当然,新的测试必须依*新的行为来运行。)
我们的立足点在哪里呢?
现在我们知道了自动化测试应该跳远的障碍:必须保证自动化测试的价值要大于采用手工测试的价值。我们需要估计一个测试的生命周期,它可以有机会创造出价值的时间段。现在,我们需要询问一下它可以创造出价值的实际可能性。我们可以期待它能发现什么样的Bug?作者: pcl2004_27 时间: 2004-6-27 11:02
测试会延续它的价值吗?
这里的争论比较复杂,所以我先给出一个大纲。
1. The code under test has structure。如一个有用的近似值,我们能把code under test分为功能代码和支持代码。
2. 测试人员编写那些有业务特色的脚本代码,其它support code对测试人员来说是不可见的。
3. 对业务代码的变动会对测试的行为产生影响。因此,因为它导致测试的死亡的可能性要比导致测试显示出一个Bug的可能性要大得多。
4. 测试的价值主要体现在当support code发生变化后发现Bug的能力。
5. 我们不知道support code的任何事情!我们怎样去知道将来测试会不会把它当作是Bug被捕获?当找到一些Bug的时候我们怎样推测整个的测试过程是正确的?
----一般情况下如果某个地方做了变动那么那里就会出现Bug。如果那里在过去做了变化那么将来这里会有更多的变更。
----我们很难知道测试是否正常的工作,但是可以说明有一个功能没有正常的进行工作。这样的测试不会自动的执行。
6. 测试下的代码同其它的产品互相的影响,这些对support code的影响比较多。我们希望由于support code导致的Bug我们可以及时发现。
----我们再来认识一个低价值测试的特征。高价值的测试不可能是一个feature-driven的测试;而通常会是一个task-driven。
次要的考虑
当我在思考做自动化测试的时候我需要在头脑中留意这样一些事情:
l 人们(用户)可以会发现自动化测试没有发现的bug。我们用来过滤掉界面上不相关的变化的工具和测试库可能同样的也会过滤掉一些古怪的bug。我曾亲眼看到一个测试员和偶然的发现当他移动鼠标的时候鼠标会不停的闪动而且这个现象不会经常的出现,对这个现象进行了深入的研究后我们发现了一个严重的bug。我听说过这样的一组测试,测试在屏幕上以X,Y为坐标显示一个图形,而这个图形测试人员在界面上无法看到,可是测试工具却可以发现它,并给出了正常的报告。
l 但是,如果测试人员非常的注意那些古怪的bug,那么会非常的辛苦而且还不会得到准确的检测结果。如果潜藏一个精确度为0.0000001的bug,人是难以发现它的,而工具就不会。注意Nyman指出工具可能分析出来人们无法见到的东西。测试工具不会紧紧局限到屏幕上可见的那一部分内容,他可以发现表明下数据结构上的问题。
l 事实上,人们不可能保证反复的以手工的方式重复输入相同数据来完成同样测试的过程丝毫不差,相反的都会有些细小的差别。例如,人们的操作犯了错误、后退、重新输入,这样有时偶然会发现在错误操作处理和support code交互之间的bug。
l 需要在不同外部配置下进行的测试尽可能多的使用自动化测试。如果需要在其它的操作系统、驱动或者第三方的函数库等情况下运行程序,理论上等同于使用不同的support code来运行程序。如果你知道将来会有这些变化,自动化测试将有很高的价值。但是,编写一个对外部配置敏感的测试其实是一个骗局。因为这样很可能使这组测试没有多少对bug的判断力而只是可以在不同的环境下运行。
l 如果在第一次运行测试的时候找到了一个bug,你清楚你应该在对bug进行修改后需要重新的对它进行测试。但是可能仅仅对这一个bug做自动化测试是不充足的。可以对这部分代码做一个标记,说明将来会对这部分做更改,这样还可以提醒你对这部分进行更多的自动化测试,如果bug出现在support code里,尤其应该这样。
l 如果你的自动化测试设计的支持性非常的出色,开发人员可以很容易的使用它,让他们做一次测试观察结果要比你把bug通过仔细的描述来再现给开发人员要快的多也好的多。这中测试的自动化执行的级别会很高。开发人员通常使用测试工具会很困难,或者没有在他们的机器上安装这些工具,再或者有一个环境对测试造成不可思议的破坏等等。如果真的让开发来运行测试有可能会阻止了他们正常的工作,浪费了当量的时间,而这些的目的只是为了避免书写详细的bug报告。
l 最让人恶心的是在手工测试中找到了bug,但是没有办法再现。可能你做了些什么,可是根本没有记住是怎么做的。自动化测试很少会出现这样的情况(尽管有时候你没有注意到它们依*了已经变化了的环境)。产品中的跟踪和日志可以给我们很大的帮助,这些对开发人员是非常有用的。如果这些东西不存在,自动化测试的工具可以用来创造类似日志的文档记录键盘和鼠标的操作信息。这种日志的使用价值以来它的可读性是怎么样的,在程序内部产生的日志文档是非常好的。根据我所见到的,大部分的测试人员可以在用来做记录的便签儿上得到很多东西。
l 一组自动化测试每天都可以对整个的项目进行一次探测。一个手工测试的努力可能保持长久的时间来对所有的功能进行重复的测试。但是在做过不正确的修改之后自动化测试会很迅速的发现它。如果原先正常工作的部分现在被破坏了,首先的一个问题是“最后修改的代码是哪一部分?”调试一天内所做的修改是一件很没有必要的事情,那么使用自动化测试来查看修改的情况是一件很高兴的事情。
注意,真正有威胁性的调试是在处理于子系统之间的关系。如果产品很大,内容很繁琐很难进行调试,这样自动化测试会有很高的价值。对任务驱动的测试更是如此(尽管他的生命周期不是很长)。
l 在程序开发者做了一个修改后,测试人员要进行检查。可以包含原有测试的主要框架,再根据具体情况做相应变化。有时候交流很贫乏,测试人员不可能及时的被告知已经修改的地方。我们运气好,往往这样做的结果是自动化测试不会正常的继续进行,导致测试者开始注意修改的地方。自动化测试组越少,发生这种可能的机会越小。(我发现自动化测试是一个拐弯抹角的花费昂*的一个基本交流的替代品。)
l 因为施行自动化测试需要时间,所以你不可能像手工测试那样在出现bug的第一间告知开发人员。如果你的最终测试报告在两个星期后发布,而这段时间开发人员又在原先的基础上做了新的功能,这样就是一个问题。
l 我们要尽力避免只是因为实现自动化测试比较容易而不是考虑发现bug的能力来组织测试。你可能会发现你自己设计的测试太过简单,而已清醒的知道因为过于简单你的测试会在产品发生变化的时候被破坏。这样简单的测试也很少会发现support code下的bug。
l 假设产品改变了它的部分功能,导致自动化测试给出不真实错误报告。我们可以通过更改我们的测试来屏蔽掉这些虚假的报告,但同时我们的做法可能降低测试发现bug的能力。这样测试功能在无形之中是衰退了的。
l 一个好的自动化测试的测试类可以按照一定的顺序执行,并且可以每日改变之间的次序。这可能是从一套特征测试创造任务驱动测试的一个廉价的方法。这是Edward L. Peters当看完这篇文章的草稿后提醒我注意的地方。Noel Nyman指出,自动化测试在利用偶然性(测试过程的顺序和输入的数据)的方面比人要好。
l 在准备开始测试之前需要做好自动化测试的准备。那样的话,写测试脚本的时间就不会占用测试时间,就不需要在手工测试和它之间困难的选择。当这种产品准备测试时,你仍然应该考虑实际上使那些脚本工作的费用。
l 一次自动化的试验可能不会有任何发现直到下一版本出现之前。.手动测试将会发现一个版本中存在的任何bug。 在当前版本发现bug要比在下一个才发现版本bug有价值的多。(如果当前版本没有成功那么就不会有下一个版本。)作者: hjh008 时间: 2005-3-14 21:42
版主能不能把完整的全文分享给我们啊!我很喜欢这篇文章!
能把翻译全文发给我吗我的邮箱:hjhcenxi@163.com 谢谢!
[ Last edited by hjh008 on 2005-3-14 at 21:53 ]作者: fzx 时间: 2005-3-29 15:13
好文章!作者: Vitamin 时间: 2005-4-6 15:41
斑竹,能把原文发给我看看么?