书名:Python自动化测试教程
ISBN:978-7-115-63145-9
本书由人民邮电出版社发行数字版。版权所有,侵权必究。
您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。
我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。
如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。
著 宋合志
责任编辑 张天怡
人民邮电出版社出版发行 北京市丰台区成寿寺路11号
邮编 100164 电子邮件 315@ptpress.com.cn
网址 http://www.ptpress.com.cn
读者服务热线:(010)81055410
反盗版热线:(010)81055315
本书基于Python语言介绍自动化测试的基本概念和技术,旨在帮助读者了解和掌握自动化测试的实现方法。本书覆盖Python基本语法、自动化测试框架、测试用例的设计方法、集成测试的自动化等重要知识,并通过实际案例演示如何使用Python编写自动化测试脚本。
本书适合测试人员和开发人员阅读。
在当今面向程序员的培训市场中,许多培训课程将重点放在软件的开发工作上,但在实际生产环境中,软件项目测试工作所耗费的时间和经费通常不会少于开发工作的时间和经费,甚至在基于敏捷开发的软件工程理念中,测试工作往往会贯穿软件的整个生命周期。基于这种教学供给与市场需求之间的落差,本书重点介绍测试工作在软件开发过程中的重要性,以及实现自动化测试的必要性和方法。为了达成这一目标,本书使用Python语言介绍实现自动化测试的方法。毕竟,基于Python语言及其运行环境的自动化测试技术已经成为当今软件测试领域中很热门的选择。
本书能帮助读者学习Python自动化测试,开启自动化测试的大门。读者可以在本书的基础上深入学习并研究Python自动化测试更高级的技术,为将来的职业发展打下坚实的基础。
本书以Selenium、Robot Framework这两个典型的自动化测试框架为中心,辅以PyTest、Jenkins这类用于自动管理测试用例的工具,详细地介绍如何基于Python语言实现自动化测试。本书从Python语言及其自动化测试框架的快速学习方法开始,循序渐进地介绍自动化测试环境的搭建方法,测试用例的设计方法,以及在持续集成条件下执行自动化测试的方法。在这一过程中,本书会提供一些测试用例,以帮助读者理解书中所介绍的测试方法。
本书共5章。
第1章对自动化测试进行概念性的知识梳理,并展示学习路线。
第2章介绍Python编程环境、基本语法和程序库。
第3章以面向Web应用程序的前端测试工作为例,介绍Selenium和Robot Framework自动化测试框架。
第4章探讨如何设计可交由自动化测试工具执行的测试用例,这也是本书的核心主题。在探讨这一主题的过程中,读者会具体了解在设计测试用例时所需要采取的基本步骤,以及常用测试策略。
第5章介绍集成测试的自动化和持续集成测试。
由于本书主要介绍如何基于Python语言及其相关框架实现自动化测试,因此笔者希望读者在阅读本书之前已经掌握了Python语言及其运行环境的基本使用方法。虽然第2章介绍了Python入门知识,但如果读者想更全面地掌握Python语言的全部特性,还需要阅读内容更全面的图书。
当然,Python社区的自动化测试框架不但琳琅满目,而且更新迭代极为迅速,这意味着等到本书出版之时,读者在自动化测试框架方面很可能已经有了更好的选择。基于“授人以鱼不如授人以渔”的原则,本书的真正目的是希望帮助读者掌握快速学习任意一种自动化测试框架的能力,这种能力才是程序员在这个快速发展的时代可持续发展的动力。
注意,书中所有针对OnlineResumes示例程序的测试用例都是基于各章中的代码占比及阅读体验等,进行综合考虑之后产生的简化版本,其中省略了一些用于实际生产环境的测试代码。因此,如果想解决实际项目中的某些具体问题,读者还需利用在本书中学到的知识来设计具有针对性的解决方案。要熟练掌握自动化测试框架,最好的办法就是尽可能地在实践中使用它们,在实际测试需求的驱动下模仿、试错并总结使用经验。本书并不鼓励读者直接复制、粘贴本书配套资源中的示例代码,而鼓励读者动手模仿书中的示例,将自己想要执行的代码输入计算机中,观察它们是如何工作的;然后,试着修改它们,并验证其结果是否符合预期。如果符合预期,就总结当下的经验;如果不符合预期,则思考应该做哪些调整。如此周而复始,才能达到事半功倍的学习效果。
最后,感谢正在阅读的你选择了本书,希望它能够帮助你更好地理解Python自动化测试的知识和技术,并帮助你提升测试能力。笔者欢迎读者提出宝贵的意见和建议,以帮助笔者不断改进和完善本书。
在Gitee网站关注“华美”(huamei88888888),即可找到本书配套的源代码。
宋合志
如今,在与程序员相关的热门岗位中,除了大家熟悉的软件开发岗位之外,还有软件测试。毕竟,几乎所有大中型的软件产品在发布前都需要完成大量的质量控制、测试和文档等工作,这些工作通常会占用整个软件项目50%的时间和总成本,而软件测试工程师就负责完成这些工作。然而,我们面对两方面的现实情况:一方面,就业市场对高水平的软件测试工程师的需求量越来越大;另一方面,很多人根本不了解这项工作的具体内容及其在软件工程中的重要性,这最终导致我国在这类优质人才供给方面存在着较大的缺口。一些调查数据显示,目前在我国软件行业每年都会新增约20万个软件测试类的岗位,但相关学校与培训机构培养出的软件测试人才不足新增需求量的10%,并且需求量与供给量间的差距仍在进一步扩大。
基于这样的市场现状,本书从零开始介绍与软件测试及自动化测试实现相关的知识,以自动化测试和测试框架开发的进阶技术为主线,以Python为编程语言,把Python语言在测试和开发上的优势充分地展现出来,致力于完整、详尽地探讨单元测试、性能测试、UI(User Interface,用户界面)测试、接口测试、集成测试等主题,并通过实践案例帮助读者快速掌握这些知识。
本章会对自动化测试的相关概念进行梳理并规划学习路线,希望读者在阅读完本章内容之后能够:
● 理解软件测试是一项怎样的工作,包括这项工作的定义、分类及原则;
● 理解在软件测试工作中实现自动化测试的意义,并了解自动化测试的核心能力及其局限;
● 了解实现自动化测试所需要学习的知识,并根据本书的内容安排规划好后续的学习方向。
在目前,软件开发团队中的各个成员(尤其是管理层)对软件测试工作的定义存在偏差。所以在正式介绍自动化测试的相关概念之前,读者需要花些时间来了解一下软件测试究竟是一项怎样的工作,即这项工作所要达成的目标、需要做的事情和要遵守的原则。
软件测试这项工作虽然属于计算机科学领域,但它同时需要考虑一些与经济学和心理学相关的因素。例如,在理想状态下,软件的开发商会希望通过软件测试工作能了解软件的所有情况,并证明它是一个“没有错误”的产品,但这个要求在实际生产环境中是无法满足的。首先,从科学的角度来说,大概率是不存在“没有错误”的软件的。其次,即使真的存在“没有错误”的软件,如果软件的测试人员想要证明“没有错误”,也需要在测试中穷举出该软件可能遇到的所有情况,并证明软件对每一种情况的应对都符合设计人员对它的预期。这从经济学角度来讲显然是不现实的,因为即使是十分简单的程序(如某一排序算法)也可能存在成千上万种的执行路径与输入/输出,恐怕没有哪一个软件的开发商能支持这种规模的软件测试工作。所以,如果读者想要真正地做好软件测试这项工作,首先要定义好工作的内容和要达成的目标,解决其中存在的主观愿望与客观成本之间的冲突问题。
而想要正确地定义软件测试的工作内容,读者首先需要对它有正确的理解。如果测试人员一开始就将这项工作定义为“证明软件的运行符合预期的过程”或者“向客户证明软件可靠的过程”,就会出现不符合科学现实的情况,就像前面说的,最终会走向证明软件“没有错误”的道路,成了不可能完成的任务。造成这种主客观冲突的主要根源在于,我们在心理上更倾向于执行具有建设性的任务,如程序员在开发软件时很自然地希望得到项目经理和客户的认可,所以行为上会下意识地去制造软件可靠且符合预期的表象。但软件测试的真正目标在于发现软件中还没有被发现的错误,或者所有人都没有预期到的情况,以便开发人员能继续提升软件的质量。换言之,软件测试本质上是破坏性任务,测试人员要做的实际上是类似于“鸡蛋里挑骨头”的工作。
想要让人们克服心理障碍,转而干“挑刺”工作,首先需要明确目标。具体来说,测试人员不能认为“没有发现错误”的测试是成功的测试,软件测试工作的目标是尽可能地找到软件中可以重现给其开发人员的错误。这就好像病人到医院看病,如果做了大量检查之后什么问题都没有找到,这显然不是一次成功的检查,毕竟只有找到病因,医生才能对症下药。只有怀揣这样的目标,测试人员才能确保自己不会在无意中做一个“老好人”,而会从一开始就铁了心做一个千方百计“刁难”待测软件的“坏人”。
综上所述,软件测试应该被定义成“为了发现错误而执行程序”的工作。
如果读者想要对软件测试这项工作建立全面的认知,除了理解软件测试工作的定义之外,还要了解在这项工作中可以执行哪些类型的测试。基本上,人们可以基于软件测试工作的各种不同目标和需求,在软件测试工作中执行如下测试。
● 单元测试。单元测试通常是指对软件中的最小可测试单元进行检查和验证。至于“单元”的大小或范围,并没有明确的标准,“单元”可以是函数、方法、类、功能模块或者子系统。值得一提的是,人们往往将单元测试和白盒测试联系到一起,虽然从概念上来说,两者是有区别的,但单元测试和白盒测试通常都可被看作针对代码逻辑的测试,所以在某些语境下也可以认为这两者相同。
● 性能测试。性能测试是指通过设计一些特定的测试用例来模拟多种正常、峰值和异常负载条件等,从而对系统的各项性能进行测试。负载测试和压力测试都属于性能测试,两者可以结合进行。负载测试可用于确定在各种工作负载下系统的性能,目标是测试当负载逐渐增加时系统各项性能的变化情况。压力测试是通过确定系统的瓶颈或者不能接受的性能点来测试系统能提供的最大服务级别的。
● UI测试。在UI测试中,测试人员会通过设计一些特定的测试用例模拟用户在应用程序界面[如CUI(Command User Interface,命令行界面)、GUI(Graphical User Interface,图形用户界面)或Web界面]上进行的单击/双击、键盘输入等交互操作。在该测试过程中,这些测试用例会将模拟操作得到的反馈与一般情况下的人机交互反馈进行对比,以便找出UI的设计缺陷。
● 接口测试。接口测试是最常见的软件测试之一,它通常需要测试人员能够排除GUI的影响,并针对软件的功能进行测试。它是软件业务逻辑测试中非常关键的任务。通常在软件项目的早期,接口测试就会同步进行,以便随时找出代码中存在的各种错误。另外,由于接口测试不使用GUI,因此它主要通过字符界面与测试人员进行交互。
关于上述类型的测试工作的具体执行方式,本书第4章会详尽介绍。在这里,读者只需要先对测试工作的分类有概念性认识即可。
在了解了测试工作中所要做的事情及其要达成的目标之后,读者接下来要考虑的就是如何做好一个铁了心要“刁难”待测软件的“坏人”了。如果我们想在测试工作中扮演好这种“坏人”的角色,就需要在工作实践中建立起一些基本原则,按照《软件测试的艺术》①这本书中的建议,我们可以归纳出如下工作原则。
① 《软件测试的艺术》(The Art of Software Testing)是软件测试领域的经典著作,书中对软件测试的任务类型、测试用例的设计方法、测试策略等主题都有精彩且具体的论述,其中的许多经典论断至今仍被广泛引用。特别值得一提的是,此书仅100多页,非常适合专业人员每年精读一次,每次都会有新的感悟。
● 程序员或开发团队应该避免测试自己编写的软件。这很好理解,既然软件测试工作的本质是对待测软件进行各种“刁难”,那么自然要对自己的作品进行回避,否则很难保证测试结果不受测试人员的主观心理影响。
● 在测试用例中必须提出对软件输出或执行结果的预期。或许很多人不相信,这个再正常不过的工作原则恰恰是软件测试工作中最常见的疏忽之一。这其实是心理学问题,即如果测试人员没有就测试用例在待测软件上得到的执行结果做出明确且清晰的预期,根据“所见即所想”现象,某个似是而非的、实际上是错误的结果就可能会下意识地被解释成正确的结论。而纠正这种下意识行为的一种方法,就是事先精确预期软件的输出,鼓励人们对所有的输出进行仔细检查。
● 每个测试用例的执行结果都应该得到充分的检查。这也是一个显而易见但很容易被忽视的原则。我们经常会看到,即便某个错误的“症状”在测试用例的输出结果中已经清晰可见,测试人员也没有注意到这个错误的存在。
● 测试过程中不仅要考虑有效的数据和可以预期的执行结果,还要考虑无效的数据和预计不到的执行结果。测试人员在测试软件时通常有一个很自然的倾向,即将测试重点集中在有效和可以预期的输入情况上,而忽略无效和无法预料到的情况。然而,软件产品在使用过程中发现的许多问题往往是在它们以某些新的或未预料到的方式运行时发现的。因此,针对未预料到的和无效输入情况的测试用例通常比针对可以预期的和有效输入情况的测试用例更具有价值。
● 测试过程中不仅要观察软件是否做了它该做的事情,还要关注它是否做了它不该做的事情。这个原则是上一个原则的必然结果,必须检查软件是否有其开发者不希望出现的操作。例如,如果某个公司的工资管理系统可以为公司的每个员工生成正确的工资单,我们就可以认为它做了该做的事情,但如果该系统为公司的非雇员也生成了相应的工资单,这就是一个不小的错误,测试人员的职责就是发现它做了这件不该做的事情。
● 测试人员使用的测试用例应该是可以重复执行的,测试用例的执行结果也应该是可以重现的。这个原则也是非常重要且显而易见的,试想一下,如果测试人员精心设计的测试用例在他发现某个错误并提交报告之后就被丢弃了,那么一旦软件在完成修改之后需要重新测试,测试人员就必须重新设计这些测试用例。这不仅是对人力资源的巨大浪费,而且测试人员很难保证重新设计的测试用例能对上一次发现的已修改的错误进行确认。除此之外,软件的其他部分被修改之后,也可能导致已经被测试过的部分出现新的问题,因此需要对其进行回归测试,这也需要测试人员保留并重复执行使用过的测试用例。
● 在制订工作计划、开发测试用例时不能假设软件中不存在错误。这是项目经理经常容易犯的一种错误,因为他们对测试工作有不符合科学规律的预期。也就是说,他们误以为测试是一个“证明程序能正确运行”的过程,但测试实际上是“为发现错误而执行程序”的过程。关于这两种认知的差异及其造成的影响,本书之前已经做了详细的说明,这里不再重复。
● 软件的某一部分中可能存在的实际错误数量通常与该部分中已经发现的错误数量成正比。在各种类型的工程中,人们总会观察到错误同时出现的现象,软件工程也不例外,每个软件都免不了会出现几个出错频率很高的部分。尽管没有人能够对这种现象给出很好的解释,但这足以让测试人员积累某种工作经验。换言之,如果程序的某个部分远比其他部分更容易产生错误,那么测试人员就可以基于这种经验对这部分进行重点测试,以便让测试工作获得更高的成效。
● 明白软件测试是极富创造性的工作,它给程序员带来的挑战并不低于软件开发所带来的挑战。也许很多人没有意识到一个事实,即测试大型软件所需要完成的创造性工作在很多情况下是超过该项软件开发工作的。想要充分地测试软件并确保所有错误都不存在几乎是不可能的。这意味着测试人员需要使用一系列特定的技术,并针对具体的软件设计出合理的测试用例集,而这显然需要测试人员完成大量的创造性工作。
除了上述基本原则之外,对于某些具体的测试工作来说,妥善利用自动化测试来提升测试的效率和质量是一个非常重要的工作原则,这让自动化测试成为测试人员必须学习的一项重要技能。这项技能如今在流行的敏捷开发、持续交付和持续集成等新型软件工程理念中有着至关重要的地位。下面我们继续了解实现自动化测试的意义,以及自动化测试的核心能力及其局限性。
自动化测试实际上指的是利用计算机的自动化操作能力完成一些特定的测试任务,目的是解决人工执行的测试操作带来的各种效率和成本问题。具体来说,测试人员使用独立于待测软件之外的自动化测试脚本和其他软件工具,完成测试任务,并生成相应测试报告。在这个过程中,工程师会利用特定的软件工具记录用户操作,并在后续测试中重复这些操作,或通过编写测试用例的方式模拟人工测试。
随着人们在生产环境中开发的软件系统在规模上越来越庞大,人们对这些软件系统进行测试也变得更加困难和复杂,这使传统的人工测试越来越难以胜任相关的工作。因此,测试人员越来越需要利用自动化测试技术克服传统测试技术的许多问题,在原则上,只要某一软件的测试流程是确定了的,实现针对它的自动化测试在理论上就具备一定的意义。毕竟这样做既可以从工作效率的角度快速执行一些重复但必须完成的测试工作,也可以从工作规模的角度来完成一些人工测试几乎不可能完成的任务。
当然,仅仅从理论上理解实现自动化测试的意义是不够的。毕竟,自动化测试本身会给软件项目带来高昂的成本,并且不是在所有情况下都具有良好的效果,所以还需要从实际生产需求的角度来理解为什么某些项目需要实现自动化测试,或者说这些项目在什么情况下才需要进行自动化测试。因为只有这样,读者才能在具体的测试工作中做到有的放矢,让自动化测试锦上添花,而不是画蛇添足。想要具有这种效果,我们需要明白一个项目是否该引入自动化测试取决于哪些因素。
首先,软件项目的开发时间毫无疑问是其中一个需要重点考虑的因素。如果一个软件测试项目要执行的只是一个短期任务,那么在这期间可能需要用相当长的时间来确定客户需求、编写测试用例等,实际留给测试工作的时间往往很少。在这种情况下,无论是从时间成本还是从工作效率的角度考虑,人工测试都绝对是第一选择。毕竟,项目可能连测试用例的设计工作都还没有完成,时间就过去了,且测试操作随时可能改变,在这种情况下,引入自动化测试显然是没有意义的。但是,一旦该项目变成了一个周期较长的测试任务,就可以考虑在其中引入自动化测试了。因为在这种情况下,测试用例的设计通常比较稳定,使用自动化测试对人工测试进行模拟就具有现实意义。
除了时间因素之外,我们还要考虑自动化测试所带来的实际开销和工作效率。通常情况下,自动化测试相对比较容易在大型软件企业的项目中得到实施,因为它们更有实力承担相关的成本,发挥出自动化测试技术的优势,并借助该优势来获得较高的投资回报率。这也意味着我们只有在以下几类项目中引入自动化测试,才能体现出它在软件工程中的真正价值。
● 产品型项目。这类项目的特点是通常每次修改都只涉及少量的功能,但在整个项目周期中都必须反反复复地测试那些没有改动过的功能。在这种情况下,后一部分的测试完全可以让自动化测试来承担,同时对新增功能的测试也会慢慢地加入自动化测试当中。
● 采用增量式开发、持续集成的项目。由于开发这类项目需要频繁地发布软件的新版本,因此需要频繁地进行对应的自动化测试,这样能把人力从中解脱出来以测试新的功能。
● 能够自动编译、自动发布的项目。如果想要实现完全的自动化测试,软件项目就必须具有自动编译、自动发布的能力。当然,不具有这些能力的软件项目往往可以在人工干预的情况下进行自动化测试。
● 包含大量重复性、机械性操作的项目。在这种情况下,测试人员最好的选择就是将这类烦琐的任务转化为自动化测试任务。毕竟,自动化测试非常适合执行需要多次重复的、机械性的操作,例如,向系统输入大量的相似数据来进行压力测试并生成相应的报表。
● 需要频繁执行某一测试任务的项目。测试人员如果发现在一个项目中需要频繁地执行某一测试任务,且测试的周期按天计算,那么就应该最大限度地使将这一测试任务的执行自动化。
需要提醒读者的是,在考虑项目中引入自动化测试的意义时,千万不要将人工测试与自动化测试的关系对立起来。如今,有许多人误以为只要采用了自动化测试,项目中就不需要人工测试了,甚至认为实现自动化测试的意义就是有朝一日替代项目中所有的人工测试,这样做就本末倒置了。事实上,二者并不是对立的,人工测试的执行主体是人类,主要通过人为的逻辑判断验证当前的步骤是否正确,往往有较强的随机应变能力,但在测试步骤之间可能存在思维比较跳跃、缺乏稳定性之类的问题。而自动化测试的执行主体是自动化测试脚本,主要通过预先定义的逻辑规则验证当前的步骤是否正确,且自动化测试的测试步骤之间关联性强,不像人工测试那样能应对突发状况。由于两者在测试工作中是互补关系,因此优秀的测试工程师应该学会善用自己的技能,做好人工测试与自动化测试的分工。这就需要他们充分理解自动化测试的核心能力,以及这种能力的局限性。
从具体工作内容上来说,自动化测试的核心就是通过制定一套严密的测试法则和评估标准,从而定义出完整的自动化测试流程。也正因为如此,它才可以有效地避免测试工程师的某种惯性思维或迷信经验导致的测试疏漏。我们通过具体实例了解自动化测试在具体测试任务中的作用。
首先,让我们来看单元测试。这类测试的自动化是极限编程和性能驱动开发等新型开发方式的一个关键衍生,由它主导的开发过程通常被称为测试驱动开发。在这类开发活动中,单元测试的用例可以在开发人员编写完应用程序的业务代码之前就设计,并作为对这一部分业务目标是否被达成的一种判定。随着代码编写进度的不断推进,单元测试同步进行,代码中存在的缺陷也将被不断找出,并被持续纠正和完善。由于开发人员能够及时发现缺陷,然后立即做出改变,因此修复的代价大大减小,这种持续发展的开发方式比瀑布模型这类开发结束再测试的方式更可靠。正因为如此,在项目开发过程中使用单元测试框架实现自动化测试已经成为目前软件开发行业的一大趋势。
然后,介绍回归测试。如果读者之前做过一些软件测试工作,应该知道如果以人工测试的方式对大量的低级接口进行回归测试将是一件十分耗时的事情,况且通过这种方式寻找缺陷的效率非常低。而一旦这部分的测试实现了自动化,日后的测试工作将可以高效、循环地完成,很多时候这是针对软件产品进行长期回归测试的高效方法。毕竟,早期一个微小的补丁中引入的回归问题可能在日后导致巨大的损失。
当然,凡事都有局限性,事情做过了就会带来反面效果。尽管从整个软件开发周期来看,自动化测试可以节省软件开发活动的开支,但如果一味地追求将所有的测试工作完全自动化,那么自动化测试本身的实现有可能会在短期内给项目团队带来巨大的开销。毕竟,测试本身虽然可以实现“自动化”,但对测试脚本进行维护和编写仍然需要投入大量的人力。因此在实际生产环境中,测试人员会根据软件测试的具体需求采用人工测试和自动化测试相结合的方法来完成任务。通常情况下,一项测试工作的自动化需满足以下要求。
● 对测试用例的要求。可自动化测试的测试用例大多是目标项目每次修改之后需要进行回归测试的重要部分。只有在这种情况下,对相关代码实现自动化测试才能有效地降低人工测试消耗的人力和物力。
● 对测试人员的要求。由于在自动化测试的过程中测试用例和输出结果都是以代码的形式存在的,因此这就要求测试人员自身必须具备编程语言的使用能力。当然,某些自动化测试工具支持通过关键词指定测试步骤,因此免除了编写程序的过程,在这种情况下测试人员就不需要掌握编程技术。
● 对项目团队的要求。是否要对测试过程实现自动化,最终取决于开发目标项目的团队是否真的需要自动化测试。这需要项目团队的管理者根据要被测试的目标系统、测试工作的规模和种类、可使用的测试工具、人员和组织的工作重心等因素进行综合考虑来做出决策。
对于上述要求中的最后一项,如果读者是某个项目团队的管理者,就需要具体了解究竟有哪几种测试是可以实现自动化的,只有这样才能根据项目进行回归测试的必要性、经济因素、被测系统成熟度等来做出决定。通常来说,以下类型的项目应该是不适合引入自动化测试的。
● 一次性定制的项目。对于这种为客户一次性定制的项目,因为维护期的工作由客户承担,甚至采用的开发语言、运行环境也是客户特别要求的,即公司在这方面的测试积累很少,所以这样的项目不适合引入自动化测试。
● 项目周期很短的项目。如果项目周期很短、测试周期很短,就不值得花精力去投资自动化测试。对于好不容易建立起的测试脚本,不能得到重复利用是一种浪费。
● 业务规则复杂的项目。业务规则复杂的项目往往存在很多逻辑关系、运算关系,它们是很难使用自动化测试技术来进行测试的。
● 功能与人类感官相关的项目。与UI的美观、声音的体验、易用性相关的项目通常只能进行人工测试。
● 测试任务很少的项目。如果测试任务很少,就没有必要进行自动化测试,不然就是一种浪费。自动化测试要执行的是那些需要不厌其烦、反反复复测试的项目。
● 尚未达到稳定状态的项目。如果软件项目的运行状态本身还不稳定,那么这些不稳定因素大概率会导致自动化测试失败。只有软件项目的运行达到相对稳定的状态、没有界面性严重错误和中断错误,才能开始自动化测试。
● 涉及物理设备交互的项目。如果软件项目在运行过程中需要与其他物理设备进行交互,如刷信用卡操作,那么其很难引入自动化测试。
在了解自动化测试的基本概念、核心能力及其局限性之后,我们就可以具体规划进入这一领域的学习路线了。建议如下:首先,了解在进行软件测试工作时所需要的基础知识,主要内容包括软件测试的基本策略、用例设计方法等;其次,掌握一两门在软件测试工作中需要使用的编程语言及其相关工具,如Java、Python、Ruby、JavaScript等;最后,掌握一两款当今主流自动化测试框架的使用方法。本节将基于本书后续内容给出一些更具体的学习建议,以供读者参考。
在学习软件测试的基础知识方面,除了之前提到的测试任务分类之外,我们还需要对测试要采取的策略有所了解。例如,人们经常提到的黑盒测试和白盒测试就是两种基本的测试策略。下面让我们来了解一下它们。
● 黑盒测试。这类测试策略有时也称为数据驱动的测试或输入/输出驱动的测试。在该策略之下,测试人员会将待测软件看作某种黑盒,并根据该软件开发者提供的用户手册对其进行测试,以便找出软件的输入/输出中不符合用户手册的部分。在这种情况下,测试工作与软件内部的具体实现方式完全无关,其测试用例设计的依据主要是用户手册中制定的输入规范。换言之,如果测试人员想单纯依靠这种测试策略找出待测软件中的所有错误,就需要穷举用户手册允许的所有输入。
● 白盒测试。这类测试策略有时也称为逻辑驱动的测试。在该策略之下,测试人员会将待测软件看作透明的盒子,并基于该软件内部构造对其进行测试,以便找出软件在业务逻辑实现上的错误。在这种情况下,测试工作与软件内部构造的具体实现方式息息相关,其测试用例设计的依据主要是测试人员对软件代码的审阅。换言之,如果测试人员想单纯依靠这种测试策略找出待测软件中的所有错误,就需要穷举该软件源代码中每一种可能的执行路径。
很显然,在生产环境中,无论是穷举输入还是穷举执行路径都是不现实的,因此在实际设计测试用例时,我们通常只会根据要测试的对象和具体的测试需求搭配使用以上两种策略,这需要测试人员在工作实践中不断总结经验并修正解决方案。以下就是常见的4种解决方案。
● 等价类划分法。在该解决方案中,测试人员会倾向于预先设定若干输入域的集合,相同集合中的每个输入条件都将被视为等效的,如果其中一个输入条件不能导致问题产生,那么用同一集合中的其他输入条件也不太可能在测试中发现错误。这其实是基于黑盒测试来设计的一种解决方案,它在一定程度上规避了穷举输入的必要性。
● 边界值分析法。该解决方案的理论基础是假定大多数的错误发生在各种输入条件的边界上,如果在边界附近的取值不会导致程序出错,那么其他的取值导致程序出错的可能性也很小。这也是基于黑盒测试来设计的一种解决方案,它在很大程度上减少了要测试的输入数量。
● 判定表法。判定表是分析和表达多种输入条件下系统执行不同动作的工具,它可以把复杂的逻辑关系和多种条件组合的情况表达得既具体又明确。显而易见,这是基于白盒测试设计的一种解决方案,它实际上实现了对源代码执行路径的分组测试。
● 流程分析法。在该解决方案中,测试人员会将软件系统的各种流程看成其源代码的执行路径,然后使用路径分析的方法设计测试用例。流程分析法根据各种流程的顺序对其进行组合,使流程的各个分支能够遍历。显然,这是另一种基于白盒测试设计的解决方案,它能有效地减少要测试的代码的执行路径。
关于测试用例的设计,本书第4章结合不同类型的测试任务详细介绍。在这里,读者只需要对软件测试的基本策略有概念性认识即可。
虽然在自动化测试领域测试人员可以使用的编程语言包括Java、Python、Ruby、JavaScript等,但考虑时下市场上常用的第三方框架和集成化测试工具,Python无疑是其中最经济也是最实用的选择之一,所以本书选择Python语言作为实现自动化测试的主要工具。这就意味着,如果读者想要很好地学习本书后续章节探讨的各种主题,那么掌握Python语言的基本语法及其标准库的使用方法是先决条件。本书会假定读者已经掌握了这门语言的基本使用方法,“掌握”的判定标准如下。
首先,要能正确地安装和配置Python运行环境,掌握这一能力的判定标准是读者能在自己的计算机中顺利地执行以下“Hello Python!”程序。
#! /usr/bin/env python
def main():
print("Hello Python!")
if _ _name_ _=='_ _main_ _':
main()
其次,读者需要掌握Python语言的标准语法,包括灵活运用各种表达式语句、条件语句、循环语句等,以及会使用标准库提供的各种数据类型和数据结构。掌握它的判定标准是能理解并复述以下代码中实现的4种排序算法,并能正确地调用它们。
#! /usr/bin/env python
import random
def radixSort(coll, length):
if(coll==[]): return []
for d in xrange(length):
LSD=[[] for _ in xrange(10)]
for n in coll:
LSD[n/(10**d)%10].append(n)
coll=[tmp_a for tmp_b in LSD for tmp_a in tmp_b]
return coll
def insertSort(coll):
if(coll==[]): return []
for i in range(1,len(coll)):
j=i
while j>0 and coll[j-1]>coll[j]:
coll[j-1], coll[j]=coll[j], coll[j-1]
j-=1
return coll
def shellSort(coll):
if(coll==[]): return []
size=len(coll)
step=size/2
while(step>=1):
for i in range(step, size):
tmp=coll[i]
ins=i
while(ins>=step and tmp<coll[ins - step]):
coll[ins]=coll[ins-step]
ins-=step
coll[ins]=tmp
step=step/2
return coll
def quickSort(coll):
if(coll==[]): return []
return quickSort([x for x in coll[1:] if x<coll[0]])+
coll[0:1]+quickSort([x for x in coll[1:] if x>=coll[0]])
最后,在理想的情况下,读者还应该具备针对某一特定任务导入相关的标准模块或第三方库,并编写自动化测试脚本的能力。例如,能理解并编写下面这段实现Git提交操作的自动化测试脚本。这种能力也是读者在后续章节中学习编写测试用例的基础。
#! /usr/bin/env python
import os
import sys
import time
if (not len(sys.argv) in range(2, 4)):
print("Usage: git_commit.py <git_dir> [commit_message]")
exit(1)
title="= Starting " + sys.argv[0] + "...... ="
n=len(title)
print(n*'=')
print(title)
print(n*'=')
os.chdir(sys.argv[1])
print("work_dir: " + sys.argv[1])
if (len(sys.argv)==3 and sys.argv[2] != ""):
commit_message=sys.argv[2]
else:
commit_message="committed at " + time.strftime("%Y-%m-%d",
time.localtime(time.time()))
os.system("git add .")
os.system("git commit -m '"+ commit_message + "'")
print("Commit is complete!")
print(n*'=')
print("= Done!" + (n-len("= Done!")-1)*' ' + "=")
print(n*'=')
如果读者在基于以上判定标准的自我检验中遇到了一些绕不过去的障碍,建议读者先补习Python语言的基本使用方法。为了解决这方面的问题,本书第2章中特别设置了一个专题教程,希望它能帮助读者快速上手这门语言。总而言之,读者只有掌握了Python语言,才能更好地适应后续章节的学习与实践,以便实现最好的学习效果。
自动化测试框架泛指某种为特定产品设置一系列特定测试规则并自动执行这些规则的集成系统。这套系统中通常整合了各种用于测试的函数库、测试数据集、元数据和可重用模块等。将它们按照测试需求组合起来便可以得到完整的、针对特定功能或应用场景的测试用例。自动化测试框架为自动化测试提供基础,并简化自动化测试的工作流程。
在面向Web应用程序的自动化测试工作中,Selenium和Robot Framework这两个框架是当前软件测试工程师的主流选择。其中,Selenium框架是时下在Web领域中最常用的自动化测试工具之一,它能帮助测试人员快速开发出自动化测试用例,且跨平台、跨编程语言(如Java、Python),支持在多种浏览器上开展测试工作。该框架的学习曲线比较平缓,对于编程经验不是很丰富的测试人员来说,使用Python、Selenium这一组合工具是一个很好的选择。
而Robot Framework框架则是一款更通用的、可扩展的、支持关键字驱动的自动化测试框架,通常被专业的测试工程师用于端到端的验收测试,如用于验收测试驱动开发的成果,或者用于测试分布式异构应用程序的各种接口。该框架的优势主要在于关键字驱动测试可以重复利用,易扩展,支持生成HTML(HyperText Markup Language,超文本标记语言)格式的测试报告,有庞大的测试库等。但它也存在着一些界面操作的共性问题,它在测试用例过于庞大时会产生界面卡顿的现象,并引发一些缺陷,如在导入测试库时会遇到界面卡死的情况。
基本上,只要很好地掌握了Selenium和Robot Framework这两个框架,那么无论是进行主流的、基于Web界面的自动化测试,还是面向其他UI的自动化测试,读者都能够获得一定的实践经验并能够举一反三。例如,在Android和iOS平台下进行自动化测试的Appium框架的使用方法与Selenium框架的是大同小异的。关于快速学习第三方框架的具体方法,本书第3章会详尽介绍。