我在很多软件公司工作过公司規模有大有小,也和来自其他公司的人员交流因此经历过或者听说过影响自动化测试效果的各种各样的的问题。本文将提供若干方法规避可能在自动化测试中出现的问题我先给大家讲一个故事,以便各位了解自动化测试会出现哪些问题
以前,我们有一个软件项目开發小组内所有的人都认为应该在项目中采用自动化测试。软件项目的经理是 Anita Delegate 她评估了所有可能采用的自动化测试工具,最后选择了一种并且购买了几份拷贝。她委派一位员工 ——Jerry Overworked 负责自动化测试工作 Jerry 除了负责自动化测试工作,还有其他的很多任务他尝试使用刚刚购買的自动化测试工具。当把测试工具应用到软件产品测试中的时候遇到了问题。这个测试工具 太复杂难于配置。他不得不给测试工具嘚客户支持***打了几个***最后, Jerry 认识到他需要测试工具的技术支持人员到现场帮助***测试工具,并找出其中的问题在打过几個***后,测试工具厂商派过来一位技术专家技术专家到达后, 找出问题所在测试工具可以正常工作了。这还算是顺利了但是,几個月后他们还是没有真正实现测试自动化, Jerry 拒绝继续从事这个项目的工作他害怕自动化测试会一事无成,只是浪费时间而已
项目经悝 Anita 把项目重新指派给 Kevin Shorttimer ,一位刚刚被雇佣来做软件测试的人员 Kevin 刚刚获得计算机科学的学位,希望通过这份工作迈向更有挑战性的、值得去莋的工作 Anita 送 Kevin 参加工具培训,避免 Kevin 步 Jerry 的后尘 —— 由于使用测试工具遇到困难而变得沮丧导致放弃负责的项目。 Kevin 非常兴奋这个项目的测試需要重复测试,有点令人讨厌因此,他非常愿意采用自动化测试一个主要的版本发布后, Kevin 准备开始全天的自动化测试他非常渴望嘚到一个机会证明自己可以写非常复杂的,有难度的代码他建立了一个测试库,使用了一些技巧的方法可以支持大部分 的测试,这比原计划多花费了很多时间不过, Kevin 使整个测试工作开展的很顺利他用已有的测试套测试新的产品版本,并且确实发现了 bug 接下来, Kevin 得到┅个从事软件开发职位的机会离开了自动化的岗位。
Ahmed Hardluck 接手 Kevin 的工作从事自动化测试执行工作。他发现 Kevin 留下的文档不仅少并且没有太多嘚价值。 Ahmed 花费不少时间去弄清楚已有的测试设计和研究如何开展测试执行工作这个过程中, Ahmed 经历了很多失败并且不能确信测试执行的方法是否正确。测试执行中执行失败后的错误的提示信息也没有太多的参考价值,他不得不更深的钻研一些测试执行 看起来仿佛永远沒有结束。另外一些测试执行需要一些特定的测试环境搭建要求他更新测试环境搭建文档,坚持不懈地工作后来,在自动化测试执行Φ它发现 几个执行失败的结果,经过分析是回归测试的软件版本中有 BUG ,导致测试执行失败发现产品的 BUG 后,每个人都很高兴接下来,他仔细分析测试套中的内容希望通过优化测试套使测试变得更可靠,但是这个工作一直没有完成,预期的优化结果也没有达到 按照计划,产品的下一个发布版本有几个主要的改动 Ahmed 立刻意识到产品的改动会破坏已有的自动化测试设计。接下来在测试产品的新版本Φ,绝大多数测试用例执行失败了 Ahmed 对执行失败的测试研究了很长时间,然后从其他人那里寻求帮助。经过商讨自动化测试应该根据產品的新接口做修改,自动化测试才能运转起来最后,大家根 据新接口修改自动化测试测试都通过了。产品发布到了市场上接下来,用户立刻打来投诉***投诉软件无法工作。大家才发现自己改写了一些自动化测试脚 本导致一些错误提示信息被忽略了。虽然实際上测试执行是失败的,但是由于改写脚本时的一个编程错误导致失败的测试执行结果被忽略了。这个产品终于失 败了
这是我的故事。或许您曾经亲身经历了故事当中某些情节不过,我希望你没有这样的相似结局本文将给出一些建议,避免出现这样的结局
这个故倳阐明了几个使自动化测试项目陷入困境的原因:
自动化测试时间不充足:根据项目计划的安排,测试人员往往被安排利用自己的个人时間或者项目后期介入自动化测试这使得自动化测试无法得到充分的时间,无法得到真正的关注
缺乏清晰的目标:有很多好的理由去开展自动化测试工作,诸如自动化测试可以节省时间使测试更加简单,提高测试的覆盖率可以让测试人员保持更好 的测试主动性。但是自动化测试不可能同时满足上述的目标。不同的人员对自动化测试有不同的希望这些希望应该提出来,否则很可能面对的是失望
缺乏经验:尝试测试自己的程序的初级的程序员经常采用自动化自动化测试。由于缺乏经验很难保证自动化测试的顺利开展。
更新换代频繁( High turnover ):测试自动化往往需要花费很多时间学习的当自动化测试更新换代频繁的时候,你就丧失了刚刚学习到的自动化测试经验
对于絕望的反应:在测试还远没有开始的时候,问题就已经潜伏在软件中了软件测试不过是发现了这些潜伏的问题而已。就测试本身而言測试是一件很 困难的工作。当在修改过的软件上一遍接一遍的测试时测试人员变得疲劳起来。测试什么时候后结束当按照计划的安排,软件应该交付的时候测试人员的绝望 变得尤其强烈。如果不需要测试那该有多好呀!在这种环境中,自动化测试可能是个可以选择嘚解决方法但是,自动化测试却未必是最好的选择他不是一个现 实的解决方法,更像是一个希望
不愿思考软件测试:很多人发现实現产品的自动化测试比测试本身更有趣。在很多软件项目发生这样的情况自动化工程师不参与到软件测试的具体活动中。由于测试的自動化与测试的人为割裂导致很多自动化对软件测试并没有太大的帮助。
关注于技术:如何实现软件的自动化测试是一个很吸引人的技术問题不过,过多的关注如何实现自动化测试导致忽略了自动化测试方案是否符合测试需要。
你可能了解 SEI (软件工程研究所)提出的 CMM (能力成熟度模型) CMM 分为 5 个界别,该模型用来对软件开发组织划分等级 Jerry Weinberg (美国著名软件工程专家)也创建了自己的一套软件组织模型,茬他的组织模型中增加了一个额外的级别他称之为零级别。很显然一个零模式的组织实际上也是 开发软件;零模式组织中,在开发人員和用户之间没有差别 [Weinberg 1992] 恰恰在这类组织环境中,经常采用自动化测试方法因此,把资源用于自动化测试并且把自动化测试当作一个軟件开发活动对待,把软件测试自动化提升到一 级这是解决测试自动化的核心的方案。我们应该像运作其他的开发项目一样来运作软件洎动化测试项目
像其他软件开发项目一样,我们需要软件开发人员专注于测试自动化的开发任务;像其他软件开发项目一样自动化测試可以自动完成具体的测试任务,对 于具体的测试任务来说自动化开发人员可能不是这方面的专家,因此软件测试专家应该提供具体測试任务相关的咨询,并且提供测试自动化的需求;像其他软件 开发项目一样如果在开发编码之前,对测试自动化作了整体设计有助于測试自动化开发的顺利开展像其他软件开发项目一样,自动化测试代码需要跟踪和维护 因此,需要采用源代码管理像其他软件开发項目一样,测试自动化也会出现 BUG 因此,需要有计划的跟踪 BUG 并且对修改后的 BUG 进行测试。像其他软件开发项目一样用户需要知道如何使鼡软件,因此需要提供用户使用手册。
本文中不对软件开发做过多讲述我假定您属于某个软件组织,该组织已经知道采用何种合理的、有效的方法开发软件我仅仅是推动您在自动化测试开发 过程中遵守已经建立的软件开发规则而已。本文按照在软件开发项目中采用的標准步骤组织的重点关注测试自动化相关的事宜和挑战。
l 支持产品的可测试性
步骤一:改进软件测试过程
如果你负责提高一个商业交易操作的效率首先,你应该确认已经很好的定义了这个操作的具体过程然后,在你投入时间和金钱采用计算机提供一套自动 化的商业交噫操作系统之前你想知道是否可以采用更简单、成本更低的的方法。同样的上述过程也是用于自动化测试。我更愿意把 “ 测试自动化 ” 这个词解释成能够使测试过程简单并有效率使测试过程更为快捷,没有延误运行在计算机上的自动化测试脚本只是自动化测试的一個方面而已。
例如很多测试小组都是在回归测试环节开始采用测试自动化的方法。回归测试需要频繁的执行再执行,去检查曾经执行過的有效的测试用例没有因为软 件的变动而执行失败回归测试需要反复执行,并且单调乏味怎样才能做好回归测试文档化的工作呢?通常的做法是采用列有产品特性的列表然后对照列表检 查。这是个很好的开始回归测试检查列表可以告诉你应该测试哪些方面。不过回归测试检查列表只是合于那些了解产品,并且知道需要采用哪种测试方法的人
在你开始测试自动化之前,你需要完善上面提到的回歸测试检查表并且,确保你已经采用了确定的的测试方法指明测试中需要什么样的数据,并给出设 计数据的完整方法如果测试掌握叻基本的产品知识,这会更好确认可以提供上面提到的文档后,需要明确测试设计的细节描述还应该描述测试的预期结果,这 些通常被忽略建议测试人员知道。太多的测试人员没有意识到他们缺少什么并且由于害怕尴尬而不敢去求助。这样一份详细的文档给测试小組带来立竿见影的效 果因为,现在任何一个具有基本产品知识的人根据文档可以开展测试执行工作了在开始更为完全意义上的测试自動化之前,必须已经完成了测试设计文档测试 设计是测试自动化最主要的测试需求说明。不过这时候千万不要走极端去过分细致地说奣测试执行的每一个步骤,只要确保那些有软件基本操作常识的人员可以根 据文档完成测试执行工作既可但是,不要假定他们理解那些存留在你头脑中的软件测试执行的想法把这些测试设计的思路描述清楚就可以了。
我以前负责过一个软件模块的自动化测试工作这个模块的一些特性导致实现自动化非常困难。当我了解到这项工作无需在很短的时间内完成后决定制定 一个详细回归测试设计方案。我仔細地检查了缺陷跟踪库中与该模块相关的每个已经关闭的缺陷针对每个缺陷,我写了一个能够发现该问题的测试执行操作我计 划采用這种方法提供一个详细的自动化需求列表,这可以告诉我模块的那一部分最适合自动化测试在完成上述工作后,我没有机会完成测试自動化的实现工作不 过,当我们需要对这个模块做完整回归测试的时候我将上面提到的文档提供给若干只了解被测试产品但是没有测试經验的测试人员。依照文档的指导几乎不需要 任何指导的情况下,各自完成了回归测试并且发现了 BUG 。从某种角度看这实际上是一次佷成功的自动化测试。在这个项目中我们与其开发自动化测试脚本,还不如把测试执行步骤文档化后来,在其它项目中我们 开发了洎动化测试脚本,发现相关人员只有接受相关培训才能理解并执行自动化测试脚本如果测试自动化设计的很好,可能会好一些不过,經过实践我们总结出 完成一份设计的比较好的测试文档比完成一份设计良好的测试脚本简单的多。
另外一个提高测试效率的简单方法是采用更多的计算机很多测试人员动辄动用几台计算机,这一点显而易见我之所以强调采用更多的计算机是因为,我 曾经看到一些测试囚员被误导在单机上努力的完成某些大容量的自动化测试执行工作这种情况下由于错误的使用了测试设备、测试环境,导致测试没有效果因 此,自动化测试需要集中考虑所需要的支撑设备
针对改进软件测试过程,我的最后一个建议是改进被测试的产品使它更容易被測试,有很多改进措施既可以帮助用户更好的使用产品也可以帮助测试人员更好的测试产品。稍后我将讨论自动化测试的可测试需求。这里我只是建议给出产品的改进点,这样对手工测试大有帮助
一些产品非常难***,测试人员在***和卸载软件上花费大量的时间这种情况下,与其实现产品***的自动化测试还不如改进产品的***功能。采用这 种解决办法最终的用户会受益的。另外的一个处悝方法是考虑开发一套自动***程序该程序可以和产品一同发布。事实上现在有很多专门制作***程序的商用 工具。
另一些产品改进需要利用工具在测试执行的日志中查找错误采用人工方法,在日志中一页一页的查询报错信息很容易会让人感到乏味那么,赶快采用洎 动化方法吧如果你了解日志中记录的错误信息格式,写出一个错误扫描程序是很容易的事情如果,你不能确定日志中的错误信息格式就开始动手写错误扫描程 序,很可能面临的是一场灾难不要忘记本文开篇讲的那个故事中提到的测试套无法判断测试用例是否执行夨败的例子。最终用户也不愿意采用通过搜索日志的方法 查找错误信息修改错误信息的格式,使其适合日志扫描程序便于扫描工具能夠准确的扫描到所有的错误信息。这样在测试中就可以使用扫描工具了。
通过改进产品的性能对测试也是大有帮助的很显然的,如果產品的性能影响了测试速度鉴别出性能比较差的产品功能,并度量该产品功能的性能把它作为影响测试进度的缺陷,提交缺陷报告
仩面所述的几个方面可以在无需构建自动化测试系统的情况下,大幅度的提高测试效率改进软件测试过程会花费你构建自动化测试系统嘚时间,不过改进测试过程无疑可以使你的自动化测试项目更为顺利开展起来
在前面的故事中,自动化工程师和自动化测试的发起者的目标存在偏差为了避免这种情况,需要在自动化测试需求上保持一致应该有一份自动化测试需 求,用来描述需要测试什么测试需求應该在测试设计阶段详细描述出来,自动化测试需求描述了自动化测试的目标很多人认为自动化测试显然是一件好事情,但 是他们不願意对自动化测试的目标给出清晰的描述。下面是人们选用自动化测试的几个原因:
? 加快测试进度从而加快产品发布进度
? 通过减少手笁测试降低测试成本
? 测试工作可以由技术能力不强测试人员完成
? 定义测试过程避免过分依赖个人
开发管理、测试管理和测试人员实現自动化测试的目标常常是有差别的。除非三者之间达成一致否则很难定义什么是成功的自动化测试。
当然不同的情况下,有的自动囮测试目标比较容易达到有的则比较难以达到。测试自动化往往对测试人员的技术水平要求很高测试人员必须能理解充 分的理解自动囮测试,从而通过自动化测试不断发现软件的缺陷不过,自动化测试不利于测试人员不断的积累测试经验不管怎么样,在开始自动化測试之前应该 确定自动化测试成功的标准
手工测试人员在测试执行过程中的一些操作能够发现不引人注意的问题。他们计划并获取必要嘚测试资源建立测试环境,执行测试用例测试过程中,如 果有什么异常的情况发生手工测试人员立刻可以关注到。他们对比实际测試结果和预期测试结果记录测试结果,复位被测试的软件系统准备下一个软件测试用 例的环境。他们分析各种测试用例执行失败的情況研究测试过程可疑的现象,寻找测试用例执行失败的过程设计并执行其他的测试用例帮助定位软件缺陷。接下 来他们写作缺陷报告单,保证缺陷被修改并且总结所有的缺陷报告单,以便其他人能够了解测试的执行情况
千万不要强行在测试的每个部分都采用自动囮方式。寻找能够带来最大回报的部分部分的采用自动化测试是最好的方法。或许你可能发现采用自动化执行 和手动确认测试执行结果嘚方式是个很好的选择或许你可以采用自动化确认测试结果和手工测试执行相结合和方式。我听到有人讲除非测试的各个环节都采用洎 动化方式,否则不是真正意义上的自动化测试这真是胡言乱语。如果仅仅是为了寻找挑战可以尝试在测试的每个环节都采用自动化方法。但是如果寻找成功测 试的方法,请关注那些可以快速建立的可以反复利用的自动化测试。
定义自动化测试项目的需求要求我们铨面地、清楚地考虑各种情况然后给出权衡后的需求,并且可以使测试相关人员更加合理的提出自己对自动化测试的期望通过定义自動化测试需求,距离成功的自动化测试近了一步
在前面的故事当中,那个自动化测试人员在对测试方向一片茫然的情况下一头扎进了自動化测试项目中不过,在项目的进行中他得到了来自各个方面的支持。
你可能还没有认识到这一点不过,你必须验证自动化测试项目的可行性验证过程花费的时间往往比人们预期的要长,并且需要来自你身边的各种人的帮助
很多年前,我从事一个测试自动化项目嘚工作参加项目的人员有各种各样的好点子。我们设计了一个复杂的自动化测试系统并且非常努力工作去实现系 统的每个模块。我们萣期的介绍测试自动化的设计思路和工作进度甚至演示已经完成的部分功能。但是我们没有演示如何利用该套测试自动化系统如何开展实际 的测试工作。最后整个项目被取消了,此后我再也没有犯这个错误。
你需要尽可能快地验证你采用的测试工具和测试方法的可荇性站在产品的角度验证你所测试的产品采用自动化测试的可行性。这通常是很困难的需要尽 快地找出可行性问题的***,需要确定伱的测试工具和测试方法对于被测试的产品和测试人员是否合适你需要做是验证概念 —— 一个快速、有说服力的测试套可以证明你选在測试工具和测试方法的正确性,从而验证了你的测试概念你选择的用来验证概念的测试套是评估测试工具的最好的方 式。
对于很多人来說自动化测试意味着 GUI 自动化测试,我不同意这种观点我曾经做过 GUI 和非 GUI 自动化测试,并惊奇的发现这两类测试的测试计划有很大的互补性不过, GUI 测试工具很昂贵、并且过分讲究选择合适的 GUI 测试工具是很重要的,因为如果没有选择合适的测试工具,你会遇到很多不可預测的困难 Elisabeth Hendrickson 曾经写过一篇关于选择测试的工具的指导性文章 [Hendrickson 1999] 。我建议在评估测试工具中找出能够验证你的想法的证据是很重要的环节。这需要测试工具至少有一个月试用期你可能打算现在购买一份测试工具,然后直到评 估完成后再购买更多份你需要在付出大笔金钱購买测试工具的之前,找出工具存在的问题这样,你可以从测试工具供应商得到更好的帮助当你打算更换工具的 时候,你不会感觉很為难
下面是一些候选的验证概念的试验:
回归测试:你准备在每个版本运行同样的测试用例吗?回归测试是最宜采用自动化测试的环节
配置测试:你的软件支持多少种不同的平台?你打算在所有支持的平台上测试执行所有的测试用例吗如果是的,那么采用自动化测试昰有帮助的
测试环境建立:对于大量不同的测试用例,可能需要相同的测试环境搭建过程在开展自动化测试执行之前,先把测试环境搭建实现自动化
非 GUI 测试:实现命令行和 API 的测试自动化比 GUI 自动化测试容易的多。
无论采用什么测试方法定义一个看得见的目标,然后集Φ在这个目标上验证你自动化测试概念可以使自动化更进一步迈向成功之路。
步骤四:支持产品的可测试性
软件产品一般会用到下面三種不同类别的接口:命令行接口( command line interfaces 缩写 CLIs) 、应用程序接口( API )、图形用户接口( GUI )。有些产品会用到所有三类接口有些产品只用到一类戓者两类接口,这些是测试中所需要的接口从本质上看, API 接口和命令行接口比 GUI 接口容易实现自动化去找一找你的被测产品是否包括 API 接ロ或者命令行接口。有些时候这两类接口隐藏在产品的内部,如果确实没有需要鼓励开发人员在产品中提供命令行接口或者 API 接口,从洏支持产品的可测试性
下面,更多的讲解 GUI 自动化测试相关内容这里有几个原因导致 GUI 自动化测试比预期的要困难。第一个原因是需要手笁完成部分脚本绝大多数自动化测试工具都有 “ 录制回放 ” 或者 “ 捕捉回放 ” 功能,这确实是个很好的方法可以手工执行测试用例,測试工具在后台记住你的所有操作然后产生可以用来重复执行的测试用例脚本。这是一个很好的方法但 GUI 测试还是主要由手工完成。
第②个原因把 GUI 自动化测试工和被测试的产品有机的结合在一起需要面临技术上的挑战。经常要在采用众多专家意见和最新的 GUI 接口技术才能使 GUI 测试工具正常工作这个主要的困难也是 GUI 自动化测试工具价格昂贵的主要原因之一。非标准的、定制的控件会增加测试的困难解决方法总是有的,可以采用修改产品源代码的方式也可以从测试工具供应 商处升级测试工具。另外还需要分析测试工具中的 BUG ,并且给工具咑补丁也可能测试工具需要做相当的定制,以便能有效地测试产品界面上的定制控件 GUI 测试中,困难总是意外出现让人惊奇。你也可能需要重新设计你的测试以规避那些存在问题的界面控件
第三个原因, GUI 设计方案的变动会直接带来 GUI 自动化测试复杂度的提高在开发的整个过程中,图形界面经常被修改或者完全重设计这是出了名的事情。一般来讲第一个版本的图形界面都是很糟糕。如果处 在图形界媔方案不停变动的时候就开展 GUI 自动化测试是不会有任何进展的,你只能花费大量的时间修改测试脚本以适应图形界面的变更。不管怎樣即便界面的修改会导致测试修改脚本,你也不应该反对 开发人员改进图形界面一旦原始的设计完成后,图形界面接口下面的编程接ロ就固定下来了
上面提到的这些原因都是基于采用 GUI 自动化测试的方法完成产品的功能测试。图形界面接口当然需要测试可以考虑实现 GUI 測试自动化。不过你也应该考虑采用其他方法测试产品的核心功能,并且这些测试不会因为图形界面发生变化而被中断这类测试应该采用命令行接口或者 API 接口。我曾经看到有人选择 GUI 自动化测试因为,他们不打算修改被测试产品但是,最终他们认识到必须对产品做修妀以保证 GUI 测试自动化可以正常工作。无论你选择哪种方法自动化都需要对被测试的产品做修改。因此采用可编程的接口是最可靠的。
为了让 API 接口测试更为容易应该把接口与某种解释程序,例如 Tcl 、 Perl 或者 Python 绑定在一起这使交互式测试成为可能,并且可以缩短自动化测试嘚开发周期采用 API 接口的方式,还可以实现独立的产品模块的单元测试自动化
一个关于隐藏可编程接口的例子是关于 InstallShield—— 非常流行的制莋***盘的工具。 InstallShield 有命令行选项采用这种选项可以实现非 GUI 方式的***盘,采用这种方式从提前创建好的文件中读取***选项。这种方式可能比采用 GUI 的***方式更简单更可靠
另一个例子是关于如何避免基于 WEB 软件的 GUI 自动化测试。采用 GUI 测试工具可以通过浏览器操作 WEB 界面 WEB 浏覽器是通过 HTTP 协议与 WEB 服务器交互的,所以直接测试 HTTP 协议更为简单 Perl 可以直接连接 TCP/IP 端口,完成这类的自动化测试采用高级接口技术,譬如客戶端 J***A 或者 ActiveX 不可能利用这种方法但是,如果在合适的环境中采用这种方式你将发现这种方式的自动化测试比 GUI 自动化测试更加便宜更加简單。
我曾经受雇在一家公司负责某个产品 GUI 相关的自动化测试该产品也提供命令行接口,不过他们已经实现了 GUI 的自动化测试。经过一段時间的研究我发现找到图形界面中的 BUG 并不困难,不过用户并不关注图形界面,他们更喜欢使用命令行我还发现我们还没有针对最新嘚产品功能(这些功能即可通过 GUI 的方式,也可以通过命令行的方式使用)实现自动化测试我决定推迟 GUI 自动化测试,扩展命令行测试套測试新增的产品功能。现在回过头看这个决定我没有选择 GUI 自动化测试是最大的成功之处,如果采用了 GUI 自动化测试所有的时间和努力都会浪费在其中他们已经准备好做 GUI 自动化测试了,并且已经购买了一套测试工具和其他需要的东西但我知道在开展具体的 GUI 自动化测试活动Φ,会遇到各种各样的困难和障碍
无论你需要支持图形界面接口、命令行接口还是 API 接口,如果你尽可能早的在产品设计阶段提出产品的鈳测试性设计需求未来的测试工作中,你很可能成功尽可能早的启动自动化测试项目,提出可测试性需求会使您走向自动化测试成功之路。
步骤五:具有可延续性的设计
在开篇的故事中我们看到由于自动化工程师把注意力仅仅集中在如何使自动化运转起来,导致测試自动化达不到预期的效果自动化测试是一个长期的过 程,为了与产品新版本的功能和其他相关修改保持一致自动化测试需要不停的維护和扩充。自动化测试设计中考虑自动化在未来的可扩充性是很关键的不过,自 动化测试的完整性也是很重要的如果自动化测试程序报告测试用例执行通过,测试人员应该相信得到的结果测试执行的实际结果也应该是通过了。其实有很多 存在问题的测试用例表面仩执行通过了,实际上却执行失败了并且没有记录任何错误日志,这就是失败的自动化这种失败的自动化会给整个项目带来灾难性的後 果,而当测试人员构建的测试自动化采用了很糟糕的设计方案或者由于后来的修改引入了错误都会导致这种失败的测试自动化。失败嘚自动化通常是由于没有关注 自动化测试的性能或者没有充分的自动化设计导致的
性能: 提高代码的性能往往增加了代码的复杂性,因此会威胁到代码的可靠性。很少有人关心如何对自动化本身加以测试通过我对测试套性能的分析,很多测试套都是 花费大量的时间等候产品的运行因此,在不提高产品运行性能的前提下无法更有效的提高自动化测试执行效率。我怀疑测试自动化工程师只是从计算机課程了解 到应该关注软件的性能而并没有实际的操作经验。如果测试套的性能问题无法改变那么应该考虑提高硬件的性能;测试套中經常会出现冗余,也可以考虑取出测 试套中的冗余或者减少一个测试套中完成的测试任务都是很好的办法。
便于分析:测试自动化执行夨败后应该分析失败的结果这是一个棘手的问题。分析执行失败的自动化测试结果是件困难的事情需要从多方面着手,测试 上报的告警信息是真的还是假的是不是因为测试套中存在缺陷导致测试执行失败?是不是在搭建测试环境中出现了错误导致测试执行失败是不昰产品中确实存在 缺陷导致测试执行失败?有几个方法可以帮助测试执行失败的结果分析某些方法可以找到问题所在。通过在测试执行の前检查常见的测试环境搭建问题从而提高 测试套的可靠性;通过改进错误输出报告,从而提高测试自动化的错误输出的可分析性;此外还可以改进自动化测试框架中存在的问题。训练测试人员如何分析测 试执行失败结果甚至可以找到那些不可靠的、冗余的或者功能仳较独立的测试,然后安全地将之删除上面这些都是减少自动化测试误报告警、提高测试可分析性 的积极有效的方法。另外有一种错誤的测试结果分析方法,那就是采用测试结果后处理程序对测试结果自动分析和过滤尽管也可以采用这种测试结果分析方法, 不过这种方法会使自动化测试系统复杂化更重要的是,后处理程序中的 BUG 会严重损害自动化测试的完整性如果由于自动化测试本身存在的缺陷误紦产品中的正常功能视为异常,那该怎么办我曾经看到测试小组花费开发测试自动化两倍 的时间来修改测试脚本,并且不愿意开展培训過程那些仅仅关注很浅层次测试技术的测试管理者对这种方法很感兴趣,他们排斥采用隐藏测试复杂度的方法
综上所述,应该集中精仂关注可以延续使用的测试套从以下几方面考虑,测试的可检视性、测试的可维护性、测试的完整性、测试的独立性、测试的可重复性
可读性:很多情况下,在测试人员开始测试项目之前公司已经有了一套测试脚本,并且已经存在很多年了我们可以称之为 “ 聪明的橡树 ”(wise oak tree)[Bach 1996] 。大家很依赖它但是并不知道它是什么。由于 “ 聪明的橡树 ” 类型的测试脚本缺乏可读性在具体应用中,那些脚本常常没有多夶的实用价值越来越让人迷惑。因此测试人员很难确定他们实际在测试什么,反而会导致测试 人员对自身的测试能力有过高的估计測试人员能够检视测试脚本,并且理解测试脚本究竟测试了什么这是很关键的。好的文档是解决问题的手段之一对测试脚 本全面分析昰另外一个手段。由上面两种方法可以引申出其它的相关方法我曾经在一个项目中使用过引申之后的方法。在测试脚本中插桩把所有執行的产品相关 的命令记录到日志里。这样当分析日志确定执行了哪些产品命令,命令采用了何种参数配置时可以提供一个非常好的測试记录,里面记录了自动化测试执行了什 么没有执行什么。如果测试脚本可读性不好很容易变得过分依赖并没有完全理解的测试脚夲,很容易认为测试脚本实际上做的工作比你想象中的还要多测试套 的可读性提高后,可以更容易的开展同行评审活动
可维护性:在笁作中,我曾经使用过一个测试套它把所有的程序输出保存到文件中。然后通过对比输出文件内容和一个已有的输出文件内容的差别,可 以称已有的输出文件为 “ 标准文件 ” ( “gold file” )在回归测试中,用这个方法查找 BUG 是不是明智之举这种方法太过于敏感了,它会产生佷多错误的警告随着时间的推移,软件开发人员会根据需要修改产品的很多输出信息这会导致很多自动化测 试失败。很明显为了保證自动化测试的顺利进行,应该在对 “ 标准文件 ” 仔细分析的基础上根据开发人员修改的产品输出信息对之做相应的修改。比较好的可維护性方法是每次只检查选定的产品的某些特定输出,而不是对比所有的结 果输出产品的接口变动也会导致原来的测试无法执行或者執行失败。对于 GUI 测试这是一个更大的挑战。研究由于产品接口变化引起的相关测试修改并研究使测试修改量最小的方法,测试中采用庫是解决问题的方法当产品发生变化的时 候,只需要修改相关的库保证测试与产品的变动同步修改即可。
完整性:当自动化测试执行後报告测试执行通过,可以断定这是真的吗这就是我称之为测试套的完整性。在前面的故事中当没有对自动化测试完整性 给予应有嘚关注的时候,发生了富有喜剧性的情况我们应该在多大程度上相信自动化化测试执行结果?自动化测试执行中的误报告警是很大的问題测试人员特别 讨厌由于测试脚本自身的问题或者是测试环境的问题导致测试执行失败,但是对于自动化测试误报告警的情况,大家往往无能为力你期望自己设计的测试对 BUG 很敏感、有效,当测试发现异常的时候能够报告测试执行失败。有的测试框架支持对特殊测试結果的分类方法分类包括 PASS , FAIL 和第三种测试结果 NOTRUN 或者 UNRESOLVED 无论你怎么称呼第三种测试结果,它很好的说明了由于某些测试失败导致其他测试鼡例无法执行而并非执行失败的情况得到正确的测试结果是自动化测试完整性 定义的一部分,另一部分是能够确认执行成功的测试确确實实已经执行过了我曾经在一个测试队列中发现一个 BUG ,这个 BUG 引起测试队列中部分测试用例被跳过没有执行。当测试队列运行完毕后沒有上报任何错误,我不得不通过走读代码的方式发现了这个 BUG 如果,我没有关注到这个 BUG 那么可能在认识到自动化测试已经出现问题之湔,还在长时间运行部分测试用例
独立性:采用自动化方法不可能达到和手工测试同样的效果。当写手工测试执行的规程时候通常假萣测试执行将会由一个有头脑、善于思考、具有观察力 的测试人员完成的。如果采用自动化测试执行是由一台不会说话的计算机完成的,你必须告诉计算机什么样的情况下测试执行是失败的并且需要告诉计算机如何 恢复测试场景才能保证测试套可以顺利执行。自动化测試可以作为测试套的一部分或者作为独立的测试执行测试都需要建立自己所需要的测试执行环境,因此保 证测试执行的独立性是唯一嘚好方法。手工回归测试通常都相关的指导文档以便一个接着一个有序地完成测试执行,每个测试执行可以利用前一个测试执行创建的 對象或数据记录手工测试人员可以清楚地把握整个测试过程。在自动化测试中采用上述方法是经常犯的错误这个错误源于 “ 多米诺骨牌 ” 测试套,当一个测试执行失败会导致后续一系列测试失败。更糟糕的是所有的测试关联紧密,无法独立的运行并且,这使得在洎动化测试中分析合法的执行失 败结果也困难重重当出现这种情况后,人们首先开始怀疑自动化测试的价值自动化测试的独立性要求茬自动化测试中增加重复和冗余设计。具有独立性的测试对 发现的缺陷的分析有很好的支持以这种方式设计自动化测试好像是一种低效率的方式,不过重要的是在不牺牲测试的可靠性的前提下保证测试的独立性,如果测 试可以在无需人看守情况下运行那么测试的执行效率就不是大问题了。
可重复性:自动化测试有时能够发现问题有时候又无法发现问题,对这种情况实在没有什么好的的处理办法因此,需要保证每次测试执行的时候测试 是以同样的方式工作。这意味着不要采用随机数据在通用语言库中构造的随机数据经常隐藏初始化过程,使用这些数据会导致测试每次都以不同的方式执行这 样,对测试执行的失败结果分析是很让人沮丧的这里有两个使用随机數据发生器的的方法可以避免上述情况。一种方法是使用常量初始化随机数据发生器如果你 打算生成不同种类的测试,需要在可预测並且可控制的情况下建立不同类型的随机数据发生器。另外一个办法是提前在文件中或数据库中建立生成随机测试数据 然后在测试过程Φ使用这些数据。这样做看起来似乎很好但是我却曾经看到过太多违反规则的做法。下面我来解释到底看到了什么当手动执行测试的時候,往往 匆匆忙忙整理文件名和测试数据记录当对这些测试采用自动化测试方法,该做哪些工作呢办法之一是,可以为测试中使用嘚数据记录给固定的命名如果这些数 据记录在测试完成后还要继续使用,那么就需要制定命名规则避免在不同的测试中命名冲突,采鼡命名规则是一种很好的方法然而,我曾经看到有些测试只是随 机的命名数据记录很不幸,事实证明采用这种随机命名的方式不可避免的导致命名冲突并且影响测试的可重复性。很显然自动化工程师低估了命名冲突的可能 性。下面的情况我遇到过两次测试数据记錄的名字中包含四个随机产生的数字,经过简单的推算如果我们采用这种命名方式的时候如果测试使用了 46 条记录,会存在 10% 冲突的可能性如果使用 118 条记录,冲突的几率会达到 50% 我认为测试当中使用这种随机命名是出于偷懒的想法 —— 避免再次测试之前写代码清除老的数据記录,这样引入了问题损害了测试的可靠性和测试的完整性。
测试库:自动化测试的一个通用策略是开发可以在不同测试中应用的测试函数库我曾经看到过很多测试函数库,自己也写了一些当要求测试不受被测试 产品接口变动影响的时候,采用测试库方法是非常有效嘚不过,根据我的观察测试库已经使用的太多了已经被滥用了,并且测试库往往设计的不好没有相关的 文档支撑,因此使用测试庫的测试往往很难开展。当发现问题的时候往往不知道是测试库自身的问题,还是测试库的使用问题由于测试库往往很复杂,即便在 發现测试库存在问题相关的维护人员也很不愿意去修改问题。通过前文中的论述可以得出结论,在一开始就应该保证测试库设计良好但是,实际情况是测试自 动化往往没有花费更多的精力去保证一个优良设计的测试库我曾经看到有些测试库中的功能根本不再使用了戓仅仅使用一次。这与极限编程原则保持一致即 " 你将不需要它 " 。这会导致在测试用例之间的代码出现一些重复我发现微小的变化可能仍然存在,很难与测试库功能协调你可能打算对测试用例作修改,采用源代码的方式比采 用库的方式更容易修改如果有几个测试,他們有某些共同的操作我使用剪切和粘贴的方式去复制代码,有的人认为我采用的方法不可理喻这允许我根据需要修 改通用代码,我不必一开始尝试和猜测如何重用代码我认为我的测试是很容易读懂的,因为阅读者不必关心任何测试库的语法这种办法的优势是很容易悝解测 试,并且很方便扩展测试套在开发软件测试项目的时候,大多数程序员找到与他们打算实现功能类似的源代码并对源代码做修妀,而不是从头开始写代码同 样,在写测试套的过程中可以采用上述方法这也是代码开发方式所鼓励的方法。我比较喜欢写一些规模仳较小的测试库这些库可以被反复的使用。测试库的开发 需要在概念阶段充分定义并且文档化,从始至终都应该保持我会对测试库莋充分的测试后,才在测试中使用这些测试库采用测试库是对所有面临的情况作权衡 的。千万不要打算写一个大而全的测试库不要希朢有朝一日测试人员会利用你的测试库完成大量的测试,这一天恐怕永远不会到来
数据驱动测试:把测试数据写入到简单表格中,这种測试技术得到了越来越广泛的应用这种方法被称为表驱动( table-driven ),数据驱动 (data-driven) 或者 “ 第三代 ” 自动化测试( "third generation" automation )这需要写一个解析器,用来解释表格中的数据并执行测试。该测试架构的最主要的好处是它允许把测试内容写在具有一定格式的表格中,这样方便数据设计 和数據的检视如果测试组中有缺少编程经验的业务专家参与测试,采用数据驱动测试方法是很合适的数据驱动测试的解析器主要是由测试庫和上层的少量开发语 言写成的代码组成的,所以上面关于测试库的说明放在这里是同样合适的。在针对上面提到的少量代码的设计、開发、测试的工作还存在各种困难。代码所采用 的编程语言是不断发展的也许,测试人员认为他们需要把第一部分测试的输出作为第②部分测试的输入这样,加入了新的变量接下来,也许有人需要让测试中 的某个环节运行一百次这样加入一个循环。你可以采用其怹语言不过,如果你预料到会面临上述情况的时候那么做好采用一些能够通过公开的渠道获取的编程 语言,比如 Perl,Python 或者 TCL 这样比设计你洎己的语言要快的多。
启发式确认:我曾经看到很多测试自动化没有真正意义上的结果校验其原因有两个,一个原因是做完全意义上的洎动化测试结果确认从技术上讲是很困难 的另外一个原因是通过测试设计规格很难找出自动化测试的预期结果。这很不幸不过,采用掱工校验测试结果的方法是真正意义上的测试校验标准文件( Gold file )是另外一中校验测试结果的方法。首先捕获被测试程序的输出,并检視程序的输出然后,把输出信息文档化并归档,作为标准文件以后,自动化测试结果 与标准文件作比较从而达到结果校验的目的。采用标准文件的方法也有弊端。当产品发生变化自动化测试的环境配置发生变化,产品的输出发生变化的时候 采用标准文方法,會上报大量的误报告警做好的测试结果校验方法是,对输出结果的特定内容作分析并作合理的比较。有时候很难知道正确的输出结果是什么 样的,但是你应该知道错误的输出结果是什么样的开展启发式的结果校验是很有帮助的。我猜想一些人在自动化测试中设计了夶而全的测试结果校验方法是因为 担心如果结果校验漏掉了任何信息,可能导致自动化测试自身出现错误不过,我们在测试过程中往往采用折衷的做法没有采用大而全的测试结果校验方法,这样 就不得不面对少量漏测情况的出现的风险自动化测试不能改变这种情况嘚出现。如果自动化工程师不习惯采用这种折衷的方法那么他必须找相关人员咨询,寻找 一种合适的测试结果校验策略这需要有很大嘚创造性。目前有很多技术可以保证在不产生误报告警的情况下找到被测试产品的缺陷。
把注意力放在通过设计保证测试的可延续性上选择一个合适的测试体系架构,你将进一步迈向成功的自动化测试
在前面的故事中,当自动化工程师没有提供打包后的自动化测试程序给测试执行人员会影响到测试执行,测试执行人员不得不反过来求助自动化工程师指出如何使用自动化测试程序
作为自动化工程师,你知道如何利用自动化方法执行测试和分析执行失败的结果不过,测试执行人员却未必知道如何使用自动化测试因此,需要提供自 動化测试程序的***文档和使用文档保证自动化测试程序容易***和配置。当***的环境与***的要求不匹配出现***错误的时候,能够给出有价值的提示信 息便于定位***问题。
能够把自动化测试程序和测试套作为产品对待那真是太好了。你应该对自动化测试程序和测试套开展测试保证它们不依赖于任何专用的库或者是设备上的任何其他程序。
保证其他测试人员能够随时利用已经提供的自动化測试程序和测试套开展测试工作;保证自动化测试是符合一般测试执行人员的思维习惯的;保证测试执行人员能够理解测试结果并能够囸确分析失败的测试执行结果;这需要自动化工程师提供自动动化测试相关的指导性文档和培训。
作为测试管理者你希望在自动化工程師离开前,能够识别并修改测试套中的所有问题自动化工程师迟早会离开的,如果你没有及时的把测试套中的问题提出来就会面临废棄已有的测试套的决定。
良好的测试套有多方面的用处良好的测试套支持对产品新版本的测试;良好的测试套在新的软件平台上可以很方便的验证产品的功能;良好的测试套支持每天晚上开始的软件每日构造过程;甚至开发人员在代码 check in 之前,用良好的测试套验证代码的正確性
测试套的共享也很重要。很难预见以后什么人会继续使用你开发的测试套因此,尽量让产品开发测试团队中的成员都很容易获得伱的测试套可以把测试 套放在公司的内部网络上,这是个很好的办法这样,大家就不必为了获取一份需要的测试套而四处打听有些囚总是感觉自己的测试套还没有最终完工或者不够完 美,而没有拿出来与人分享这种做法一定要改变,共享出来的测试套不一定非常完媄共享才是关键。
有计划的自动化测试部署保证你的测试套能够被产品相关人员获取到,你就向成功的自动化测试又迈进了一步并苴你的自动化测试会被一次又一次的重用。
步骤七:面对成功的挑战
当你完成了所有的事情测试套已经文档化了,并且文档已经交付了测试执行人员能够理解要开展的测试,并知道如何完成测试执行随着你所负责产品 的进一步开发和维护,测试被反复重用虽然,在洎动化使测试变简单的同时也总是使测试过程复杂化。测试人员需要学习如何诊断自动化测试执行失败的情况 如果不这样做,测试执荇人员会认为执行失败的情况是由自动化引起然后,自动化工程师被叫过来帮助诊断每一个执行失败的情况开发人员往往也会认为执荇失 败是由于自动化测试自身引起的问题,这样测试执行人员就不得不学习通过手工的方式,或者通过采用少量脚本的方式重现自动化測试发现的问题以证明他们确 实发现了产品当中的 BUG 。
测试套的相关工作还没有结束为了提高测试覆盖率或者测试新的产品特性,需要增加更多的测试如果已有的测试不能正常工作,那么需要对之修改;如果已有的测试是冗余的那么需要删除这部分测试。
随着时间的嶊移开发人员也会研究你设计的测试,改进产品的设计并且通过模拟你的测试过程对产品做初步测试研究如何使产品在第一次测试就通过, 这样你设计的测试很可能无法继续发现新的问题,这种现象被称为一种杀虫剂悖论这时候,会有人对你的测试有效性提出质疑那么,你必须考虑是否应该挖掘 更严格的测试以便能够发现开发人员优化之后的产品中的缺陷。
以前我提到过一个基本上无法实现嘚设想,设想通过按下一个按钮就完成了所有的测试工作自动化测试是不是全能的,手工测试是永远无法完全替代的
有些测试受测试環境的影响很大,往往需要采用人工方法获取测试结果分析测试结果。因此很难在预先知道设计的测试用例有多大的重用性。自动化測试还需要考虑成本问题因此,千万不要陷入到一切测试都采用自动化方法的错误观念中
我曾经主张保证给与测试自动化持续不断的投入。但是在开展自动化测试的时候,一个问题摆在面前测试自动化应该及时的提供给测试执行人员,这个 不成问题但是如何保证需求变更后,能够及时提供更新后的自动化测试就是个大问题了如果自动化测试与需求变更无法同步,那么自动化测试的效果就无法保證 了测试人员就不愿意花费时间学习如何使用新的测试工具和如何诊断测试工具上报的错误。识别项目计划中的软件发布日期然后把這个日期作为里程碑,并计划 达到这个里程碑当达到这个里程碑后,自动化工程师应该做什么呢如果自动化工程师关注当前产品版本嘚发布,他需要为测试执行人员提供帮助和咨询但是, 一旦测试执行人员知道如何使用自动化测试自动化测试工程师可以考虑下一个蝂本的测试自动化工作,包括改进测试工具和相关的库当开发人员开始设计产品下 一个版本中的新特性的时候,如果考虑了自动化测试需求那么自动化测试师的设计工作就很好开展了,采用这种方法自动化测试工程师可以保持与开发周期同 步,而不是与测试周期同步如果不采用这种方式,在产品版本升级的过程中自动化测试无法得到进一步的改进。
持续在在自动化投入你会面临成功的挑战,当洎动化测试成为测试过程可靠的基础后自动化测试的道路将会越来越平坦。
1、分石头问题分为五份还要多┅,最后取一份+1
2、多线程的死锁问题:
死锁——当线程任务中出现了多个同步(多个锁)时如果同步中嵌套了其他的同步。这时容易引发一種现象:程序出现无限等待这种现象我们称为死锁。
即:多个线程中程序相互竞争资源的问题
3、自旋锁(spinlock)的主要缺点:
自旋锁——通過busy-wait-loop的方式来获取锁且任时刻只有一个线程能够获得锁,如果此时其他线程请求锁就会进入忙等待。
自旋锁可能存在的两个问题:死锁(想递归获得自旋锁时会导致死锁)、过多占用CPU资源(为了防止申请程序不断等待一般自旋锁会限制程序的尝试次数)
自旋锁在执行过程中会锁总线(bus),导致其他程序无法使用总线
5、使用TCP协议的通信:
TCP协议不是应用层而是传输协议层
7、一个程序中所含有的路径数与程序嘚复杂度有着直接的关系
程序的复杂度即算法的复杂度,主要由时间复杂度+空间复杂度两个方面来考虑
//对象的定位和操作是自动化测试嘚核心
9、不适合用自动化的测试:
在系统功能的逻辑测试、验收测试、适用性测试、涉及物理交互性测试时也很难通过自动化测试来实現,多采用黑盒测试的手工测试方法;
单元测试、集成测试、系统负载或性能测试、稳定性测试、可靠性测试等比较适合采用自动化测试;
//回归测试的自动化测试的强项
//性能、压力测试都适合用自动化测试
10、Android系统的四层架构:操作系统层(OS)、各种数据库、应用程序框架、應用程序
13、变量S未初始化时的java输出:提示未初始化变量如果是基本数据类型,则会有初始值如果不是,则一般是null
在类中定义的成员变量如果你没有初始化java会自动帮你初始化,如果是数字会自动初始化成0,字符会初始化成'o',对象引用会初始化成null
局部变量必须初始化否则编译会報错