软件测试新趋势

2015年11月,ThoughtWorks发布了新一期的技术雷达。技术雷达是以独特的形式记录ThoughtWorks技术顾问委员会对行业产生重大影响的技术趋势讨论的结果,为从CIO到开发人员在内的各方利益相关者提供价值。这期雷达的技术趋势主要体现在:受到热捧的微服务相关技术,逐步成熟的以Docker为典型的容器化生态系统,备受企业和用户关注的信息安全问题。本文就从这几个新趋势来分析一下给软件测试带来了哪些影响。

自动化测试是王道

在这个快速变化发展的时代,任何一款产品想要在市场具备竞争力,必须能够快速适应和应对变化,要求产品开发过程具备快速持续的高质量交付能力。而要做到快速持续的高质量交付,自动化测试将必不可少。同时,自动化测试也不是用代码或者工具替代手工测试那么简单,有了新的特点和趋势:针对不同的产品开发技术框架有着不同的自动化技术支持,针对不同的业务模式需要不同的自动化测试方案,从而使得自动化测试有着更好的可读性、更低的实现成本、更高的运行效率和更有效的覆盖率。来自技术雷达的下列主题分别体现了自动化测试的这些特点:

  • 针对微服务的消费端驱动的契约测试(Consumer-driven contract testing),有助于解决随着服务增多带来集成测试效率低和不稳定的问题。消费端驱动的契约测试是成熟的微服务测试策略中核心的组成部分。
  • 专门用于测试和验证RESTful服务的工具REST-assured,它是一个Java DSL,使得为基于HTTP的RESTful服务编写测试变得更加简单。REST-assured支持不同类型的REST请求,并且可以验证请求从API返回的结果。它同时提供了JSON校验机制,用于验证返回的JSON数据是符合预期的。
  • 安卓系统功能测试工具Espresso,其微小的内核API隐藏了复杂的实现细节,并帮助我们写出更简洁、快速、可靠的测试。
  • ThoughtWorks开源的轻量级跨平台测试自动化工具Gauge,支持用业务语言描述测试用例,支持不同的编程语言,支持所支持平台的并行执行。
  • 用于针对UI的自动化测试构建页面描述对象的Ruby库Pageify,该工具关注于更快的执行测试以及代码的可读性,并可以很好的配合Webdriver或是Capybara使用。
  • 专门用于iOS应用开发的开源行为驱动开发测试框架Quick,支持Swift、Objective-C,它和用来做测试验证的Nimble捆绑发布。Quick主要用于Swift和Objective-C程序行为的验证。它和 RSpec和Jasmine具有相同的语法风格,基础环境很容易建立。Quick良好的结构和类型断言使得测试异步程序更加容易。Quick拥有现成的Swift和Objective-C规范文件模板,开发者只需简单几步,即可对应用进行快速测试。

工具很重要,设计不可少!自动化测试工具云集,但做自动化也不要冲动,需要重视以下几点:

  1. 综合考虑项目技术栈和人员能力,采用合适的框架来实现自动化;
  2. 结合测试金字塔和项目具体情况,考虑合适的测试分层,如果能够在底层测试覆盖的功能点一定不要放到上层的端到端测试来覆盖;
  3. 自动化测试用例设计需要考虑业务价值,尽量从用户真实使用的业务流程/业务场景来设计测试用例,让自动化优先覆盖到最关键的用户场景;
  4. 同等看待测试代码和开发代码,让其作为产品不可分割的一部分。

1221-测试-automation

云技术、容器化和开源工具使得测试成本下降

测试环境的准备在过去是一个比较麻烦和昂贵的事情,很多组织由于没有条件准备多个测试环境,导致测试只能在有限的环境进行,从而可能遗漏一些非常重要的缺陷,测试的成本和代价很高。随着云技术的发展,多个测试环境不再需要大量昂贵的硬件设备来支持,加上以Docker为典范的容器技术生态系统也在逐步成长和成熟,创建和复制测试环境变得简单多了,成本大大的降低。技术雷达推荐的凤凰环境(Phoenix Environment),它使用凤凰服务器(Phoenix Server)的模式,能够以自动化的方式支持测试、开发、UAT和灾难恢复所需的新环境准备。这一技术由上期的评估环上升到了采用环,表明它已经得到了验证和认可,是可以放心使用的技术。

另一方面是大量开源工具的出现,这些工具往往都是轻量级的、简单易用,相对于那些重量级的昂贵的测试工具更容易被人们接受。测试工作有了这些开源工具的帮助,将更加全面、真实的覆盖到要测试的平台、环境和数据,将会加快测试速度、降低测试成本;更重要的一点,有了这些工具,让测试人员能够腾出更多的时间来做测试设计和探索性测试等更有意思的事情,使得测试工作变得更加有趣。新技术雷达提到的开源工具有:MountebankPostmanBrowsersyncHammsGorievms等。

  • 在企业级应用中,对组件进行良好的测试至关重要,尤其是对于服务的分离和自动化部署这两个关系到微服务架构 是否成功的关键因素,我们更需要更合适的工具对其进行测试。Mountebank就是一个用于组件测试的轻量级测试工具,可以被用于对 HTTP、HTTPS、SMTP和TCP进行模拟(Mock)和打桩(Stub)。
  • Postman是一个在Chrome中使用的REST客户端插件,通过Postman,你可以创建请求并且分析服务器端返回的信息。这个工具在开发新的API或者实现对于已有API的客户端访问代码时非常有用。Postman支持OAuth1和OAuth2,并且对于返回的JSON和XML数据都会进行排版。通过使用Postman,你可以查看你通过Postman之前发起过的请求,并且可以非常友好的编辑测试数据去测试API在不同请求下的返回。同时,虽然我们不鼓励录屏式的测试方法,但是Postman提供了一系列的拓展允许我们将它作为跑测试的工具。
  • 随着网站应用所支持设备的增多, 花在跨设备测试上的代价也在不断增大。Browsersync能够通过同步多个移动设备或桌面浏览器上的手工浏览器测试来极大的降低跨浏览器测试的代价。通过提供命令行工具以及UI界面,Browsersync对CI构建非常友好,并且能够自动化像填写表单这样的重复任务。
  • 在软件开发领域,盲目地假设网络总是可靠,服务器总是能够快速并正确的响应导致了许多失败的案例。Hamms可以模拟一个行为损坏的HTTP服务器,触发一系列的失败,包括连接失败,或者响应缓慢,或者畸形的响应,从而帮助我们更优雅的测试软件在处理异常时的反应。
  • Gor可以实时捕获线上HTTP请求,并在测试环境中重放这些HTTP请求,以帮助我们使用到这些产品环境数据来持续测试我们的系统。 使用它之后可以大大提高我们在产品部署,配置修改或者基础架构变化时的信心。
  • 尽管IE浏览器的使用量日益萎缩,但对很多产品而言IE浏览器的用户群依然不可忽视,浏览器兼容性仍然需要测试。这对于喜欢使用基于Unix的操作系统进行开发的人来说还是件麻烦事。为了帮助解决这个难题,ievms提供了实用的脚本来自动设置不同的Windows虚拟机镜像来测试从IE6到Microsoft Edge的各种版本浏览器。

1221-测试-Cost+of+testing

安全测试贯穿整个生命周期

“安全是每一个人的问题”!互联网安全漏洞频繁爆发,安全问题已经成为每个产品迫切需要关注和解决的问题,安全测试将需要贯穿于软件开发的整个生命周期。同时,给软件测试人员带来了更多的机遇和挑战,要求具备更多的安全相关知识(其中还包括更多的计算机基础知识),掌握已有的安全测试相关技术,从而在软件开发的各个阶段做好安全相关的分析和测试工作。尽管有些团队已经将安全跟整个开发实践结合起来,但培养每个人在每个阶段的安全意识还相当的重要,探索新的安全测试技术、方法还有很多空间。

1221-测试-Security

技术雷达上列出的安全测试相关的技术和工具有:Bug bounties威胁建模(Threat Modelling)ZAPSleepy Puppy

  • Bug bounties是一个安全漏洞举报奖励制度,越来越多的组织开始通过Bug bounties鼓励记录常见的安全相关的Bugs,帮助提高软件质量。
  • 威胁建模(Thread modeling)是一组技术,主要从防御的角度出发,帮助理解和识别潜在的威胁。当把用户故事变为“邪恶用户故事”时,这样的做法可给予团队一个可控且高效的方法使他们的系统更加安全。
  • ZED Attack Proxy (ZAP)是一个OWASP的项目,允许你以自动化的方式探测已有站点的安全漏洞。可以用来做定期的安全测试,或者集成到CD的Pipleline中提供一个持续的常规安全漏洞检测。使用ZAP这样的工具并不能替换掉对安全的仔细思考或者其他的系统测试,但是作为一个保证我们的系统更安全的工具,还是很值得添加到你的工具集里。
  • Sleepy Puppy是Netflix公司近期开源的一款盲打XSS收集框架。当攻击者试图入侵第二层系统时,这个框架可用于测试目标程序的XSS漏洞。XSS是OWASP的Top10的安全威胁,Sleepy Puppy可以用来同时为几个应用完成自动安全扫描。它可以自定义盲打方式,简化了捕获、管理和跟踪XSS漏洞的过程。Sleepy Puppy还提供了API供ZAP之类的漏洞扫描工具集成,从而支持自动化安全扫描。

优化业务价值

大多数软件都是做项目的模式,在不同的档期内进行计划、实现和交付。敏捷开发极大的挑战了这种模式,通过在开发过程中各个阶段进行的分析和测试工作,持续的发现新的需求,使得需求更趋于合理化,更能体现业务价值。精益创业的技术,如观察需求的A/B测试,进一步削弱了这种心态。技术雷达推荐“产品优于项目(Product over project)”,认为大多数的软件开发工作应该遵循精益企业的引领,将自己定义为构建支持业务流程的产品。这样的产品并没有所谓的最终交付,更多的是一个探索如何更好的支持和优化业务流程的过程,只要业务依然有价值就会不断持续下去。

作为软件开发中的关键角色、负责软件测试的QA人员,通过从用户角度对软件的测试,结合自身对软件产品的了解,对优化业务价值将会起到举足轻重的作用。软件测试不仅是检验软件是否满足规定的需求或弄清预期结果与实际结果之间的差别的过程,还需要有意识的对需求进行持续的验证和优化,对业务的趋势和风险进行分析。如果能在开发过程中结合使用BDD(行为驱动开发)的思想,统一团队对需求的认识,利用团队的力量来优化业务将会达到事半功倍的效果。

传统方式下,QA角色主要专注于保证软件产品在类产品环境下的质量。随着持续交付的出现,QA角色逐渐转变到需要分析软件产品在产品环境下的质量。产品环境下的QA(QA in production),就是要求QA角色在做好产品上线前的质量保证工作前提下,做好软件产品在产品环境下的质量分析。具体做法有:

(一)引入产品系统的监控, 制定检测条件,找出产品环境下使用的质量度量。比如,利用网站分析工具收集用户使用应用程序的数据,分析数据量需求、产品的性能趋势、用户的地域特征、用户的行为习惯和产品在同类型产品市场的占有率等。

(二)收集产品环境下最终用户的反馈,对反馈进行分类分析。这些反馈可能有:

  • 缺陷:需要进行优先级划分,确定是否需要修复;并且对这些缺陷进行根源分析,在以后的开发过程中尽量避免同类型的缺陷再次出现。
  • 抱怨:对于抱怨需要分析其背后的原因,可能正是能够帮助我们改进和优化业务价值的好机会。
  • 建议:一般用户可能难以提出高质量的建议,需要我们在收集反馈的时候下点功夫,有针对性的去收集。一旦收集到了建议,将是对业务价值优化非常有利的。

1221-测试-QA+Practice

通过对产品环境下的软件质量进行分析,将有利于协助“产品优于项目”实践,帮助优化业务价值,做好企业产品的创新工作。需要注意的是,产品环境下的QA可能会导致有些组织走的太远而忽视产品上线前的质量保证,它只对那些已经执行并有一定程度持续交付实践的组织有价值。

总结

软件测试是一项技术工作,但软件测试领域的问题不仅仅是技术问题。随着自动化程度越来越高,不断有人怀疑QA存在的必要性,从前面的分析可以看到,新趋势给QA提出了更高的要求,带来了更多的机遇和挑战,相信好的QA是不可能简单的被取代的。

Share

软件测试反模式——杯型蛋糕

要想帮助团队制定测试策略,编写出可靠可伸缩的测试,测试金字塔是最好的方式之一。 根据我多次的使用经验来看,它真的非常有用

同时,我也经常会看到有的团队在尝试实践测试策略时掉进各种陷阱里。正如Alister Scott指出的,一个常见的陷阱就是冰淇淋甜筒状的反模式(anti-pattern)。这种模型形容在没有足够多的底层测试(单元测试、集成测试和组件测试)的情况下,创建了太多GUI(图像用户界面)测试,甚至更多的手动测试。

得益于自动化测试在软件开发界的普及,这种反模式现象正在减少。并且,加上TDD(测试驱动开发)和BDD(行为驱动开发)这些实践的大力推广和应用,我已经有很长一段时间没看到团队担心过底层测试(单元测试、集成测试、组件测试)了。

然而,与此同时我还观察到一些团队跌进了另一个非常危险的陷阱。这个新的反模式陷阱有如下非常明显的特征:

  • 不同的团队写不同层次的测试。
  • 一般由如下三类团队来写不同的测试:
    • 开发人员写单元测试,集成测试和组件测试
    • 另外一个团队通过界面来做黑盒测试
    • 手动测试员进行一系列手动测试来测试功能
  • 通常这些团队各自独立工作,合作甚少。
  • 整个项目的工作流程流水式进行,并没有同步工作。首先是开发人员写出代码和对应的测试,然后测试人员手动地测试功能,之后GUI测试人员才编写他们的测试。这一流程看起来像什么?一个小型瀑布。
  • 这三个团队在某场景是否应该被测试,或自动化测试的级别上,无法达成一致。这就导致了重复——相同的场景在不同级别上都进行了自动化测试。

在和同事PatrickTarso讨论此事时,我们对比了一下这个新的陷阱和之前提到的冰淇淋甜筒模型,然后开始思考这个新的反模式像什么。大致说来,它应该有个庞大的底部,宽阔的中部和一个巨型的顶部。Tarso灵光一闪,突然说道:“这不就是个杯型蛋糕(Cupcake)吗!” 他说得简直太对了。

 

fabiocupcakenew1_0_04444aff9e8be210d16a68f29a20fe7a

 

下面介绍一下软件测试中的杯型蛋糕反模式:

这里有一些小贴士可以助你避开这个杯型蛋糕,甚至很有希望将其“扭转”回理想的测试金字塔模型:

  • 合作:允许团队之间进行合作,然后讨论在哪一层写特定的测试才是最好的。以下是一些实用手段:
    • 同步工作:当开发一个功能时,鼓励不同的团队之间同步工作,而不是线性工作,各自为政,像一个迷你小型瀑布一样
    • 跨角色结对:支持跨角色结对。比如,在一个Story快完结时,一个开发者可以和一个测试人员结对,决定在哪儿执行自动测试
    • Story Kickoff:这里有很多方法可以采用,比如三驾马车(The Three Amigos),或者有些人称之为story kickoff,目的都是为了帮助团队分享对需求的理解,减少沟通隔阂
  • 从最底层开始测试:在条件允许的情况下,从最靠近代码的地方开始测试一个功能,降低测试的深度
  • 如果可能,尽可能合并团队:有时你并不需要不同的团队,你所需要的只是在不同职位上的不同的人。比如说一个开发者可以成为某个功能的界面测试人员,即使如果他(她)并没有参与过开发这项功能
  • 在目标上达成一致:确保每个人都有相同的目标。比如,整个团队要对什么是“完成”达成一致意见,而不是一起工作“完成开发”或者是“完成测试”
  • 同时要达成一致的,还有衡量测试工作的方式。而一旦合适的衡量方式确立了,就要避免只能应用于某一特定层次的“横向衡量”,比如靠自动化测试的用例数目来衡量界面测试的质量。更合适的衡量方式应该是“纵向”的,这样就能把所有层次都囊括进来。就用上面的例子来讲,衡量方式应该改成这样——每个story不管在哪一层(UI测试、单元测试等)都至少需要有90%的自动化测试覆盖率。如此一来,衡量方法就被共享了,达到了双赢的效果

 

fabiocupcakenew4_49b01336bfc161b4e720e3e0aee6696b

 

当一个由开发者、手动测试人员和界面测试人员组成的团队,为了达成同一目标,齐心协力相互帮助的时候,我确信这个团队能够完成更好的测试策略,更好地确保软件质量。

最后,你有什么想法?

Share

我和敏捷团队的五个约定

我——作为一名测试人员——有一个与众不同的习惯:每当要加入一个新项目的时候,我总会找到项目中的同伴,真诚而亲切地说:“为了更好地合作,我有5个约定,希望大家能尽量遵守”。

约定1. 业务分析师们,我们其实是同一个角色的两种面孔,请叫上我们参加客户需求会议

我们的团队需要让客户频繁的得到可用的软件,客户的不断反馈会给软件的未来做出最正确的方向指引。

如果我们交付的软件有很多质量的问题,存在大量的缺陷,客户会被这些缺陷的奇怪行为干扰,没有办法把注意力放在软件本身的价值是否符合他们的真正需求上, 不能给出最有价值的反馈。所以,我们只有频繁的做测试,在每次交付之前都把质量问题找出来告诉我们的团队,问题才能及时的得到改正。

而我坚信“prevention is better than cure”(预防胜于治疗),我会要把工作的重点放在预防缺陷上,这样可以节省Dev们很多修复缺陷的时间与精力。

为了达到这个目的,我需要跟你一起参加客户需求会议,尽早的了解客户需求与使用软件的惯常行为。那么在你完成需求的验收条件的定义的时候,我也基本完成了测试用例的准备。

我们可以赶在开发人员们写代码之前就告诉他们我要测什么,让他们减少因为过于乐观而漏掉的一些重要的有破坏性的情况,减少缺陷的发生。这是我测试的一项重要任务。

如果你们在大部分需求都整理好了再交给我们,我会浪费掉等待的时间。更重要的是,开发好的软件里面已经有很多本来可以不存在的缺陷在里面了,开发人员们可能需要加班加点来保证在项目最终交付时间之前把它们改好。这样很容易产生新的缺陷的。

所以,请让我尽早了解需求,请不要让我到项目后期才能开始测试。

约定2. 开发人员们,虽然你们是编写自动化测试的专家,但请听听我们意见

我知道,对于你们,自动化测试不过是利用junit, rspec, selenium,watir,uiautomation等等写出的“另一段程序”而已。而对于80%的QA来说,编写自动化测试并不是一件简单的事情。

不过我仍然相信,有测试人员介入的自动化测试更有价值。

你们用单元测试,集成测试来保证代码的质量。然而你们的这些日常测试离代码更近,离最终用户还点远。很多测试都不是在测软件功能。

你们可以把功能测试写的又快又多,而我们可以指出什么功能测试最有必要加到自动化测试中。

你们平时大部分精力都在编码上,没有太多时间去查都有什么缺陷。而我们可以指出什么地方缺陷可能会出现的比较频繁,建议在这些脆弱的地方加自动化测试。

所以请听听我们的意见,我们可以给你们提供这些信息。

约定3. 项目经理们,请不要要求我们测试软件的所有路径

软件测试是一个永无止尽的任务。基本上没有什么软件简单到我们能够尝试完它的每一个可能的路径的。就连一个看似简单的微软计算器都有无穷尽的路径,无止尽的输入,更何况比这个更复杂的商用软件。

如果你们担心没有尝试过全部的路径不可靠,疑惑我们怎么敢说这个软件质量是好的还是坏,都有什么风险。请你们先注意,我们是跟业务分析师一样,都了解软件的价值的。价值可以帮我们做出判断,什么时候可以停止测试并对客户说我们的软件已经满足您的要求了,请放心使用。

因为我们了解价值,我们可以肯定的说哪些软件的使用方式是至关重要的,哪些是不太可能出现的。我们会在全面测试了软件以后,把主要精力放在价值高的功能点上。合理的利用项目有限的时间。

因为我们了解价值,我们可以正确的把发现的问题分类。我们可以帮助dev们把精力放在重要的缺陷上,避免把时间放在对于客户微不足道却不得不花费大量精力才能修正的问题上。

所以,请不要要求我们无止尽的测试一个软件。我们了解价值,请相信我们的判断。

约定4. 迭代经理们,如果对于交付风险有任何疑问,请来询问我

BA和Dev们都是关注一个软件在什么情况是可以良好的工作。而我们除了验证这些情况以外,大量的时候都用在寻找什么样的情况软件不能正常的运行。所以除 了针对定义好的软件行为进行测试,我们还会做很多探索性测试。我们通常可以通过这样的测试发现一些没有定义的、不曾预期的行为。这些行为往往将会构成软件 交付的风险。

我们会告诉你们现在都发生了什么问题,分别分布在哪里。

我们会告诉你们,在什么情况下软件可能会有异常行为,是不是会牵连到其他的部分,是否可以绕过去。

我们会告诉你们,哪些部分功能比较不稳定,需要更多的留意。

约定5. 测试人员们,那些敏捷实践对于我们也是有用的。

结对不是dev们的专利。我不希望总见到你们独自坐在自己的位置上冥思苦想。走出去,跟其他队友多多交流!

多跟测试队友交流,pair看看设计的测试用例是不是够全面,独自一个人想到的未必足够好。他们会给你诚恳的意见的。对他们,也请一样认真对待。

如果你发现开发人员们做出的架构决定使测试工作变得更困难。那么请大声地告诉他们,design for testability(提高你们设计的可测性)。

如果你发现业务分析师写的需求无法验证,定义的客户行为不够具体,一个用户故事中包含太多了功能点,等等,那么也请大声地告诉他,INVEST(独立,可协商,价值,可估算,短小,可测)。

也请你们多跟开发人员结对写自动化测试,既可以帮助你们学习怎样更好的编写自动化测试,也能帮助开发人员们结对更多的了解用户行为。

这就是我的五个约定,它们是我在团队中顺利展开工作的基础。


作者:覃其慧,ThoughtWorks敏捷咨询师。她参与了大量的敏捷软件开发的实践和敏捷咨询。目前主要关注以价值为驱动的敏捷测试。


本文原文发表于InfoQ:http://www.infoq.com/cn/articles/thoughtworks-practice-parti

Share

敏捷测试之借力DSL

随着敏捷越来越广为人知,敏捷测试也更多受到了大家的关注。在这里,我想谈一下我在敏捷项目中遇到的一个自动化测试相关问题以及我们如何借助DSL领域专用语言来解决它。

对敏捷软件开发方法有一定了解的人都知道,敏捷软件开发过程是一个迭代式交付的过程。每个迭代相当于比较小型的交付周期。那么,为了配合频繁的软件交付,敏捷测试相对于传统测试必须要做相应的调整。这也导致了敏捷项目中的测试面临几个特有的挑战:

  1. 频繁的回归测试以确保每个迭代的成果都是可交付的
  2. 让整个开发团队参与到测试活动中以缩短质量信息的反馈周期
  3. 让客户参与到测试活动中来帮助提高测试的有效性

自动化测试在应对频繁的回归测试这个挑战上起着非常关键的作用。自动化测试做不好,团队最终会被每个迭代都会增加的回归测试工作量压垮。我经历过的一个团队,在这个团队中,大家很早就意识到了自动化测试的重要性,在自动化测试上的投入不遗余力。我们相信自动化功能测试增加到足够多的时候,它就能指导手动回归测试,保证整个交付过程顺利进行。

的确,自动化测试刚开始进行的时候,我们收益颇多。每增加一个自动化测试,我们就能减少一些手动测试。自动化测试让我们我们有比较充裕的时间来手动测试那些还没有来得及自动化的、难以被自动化的功能点上,而且还能有时间和精力做探索性测试。这个结果让团队感到生活很美好,也让我们对自动化测试坚信不疑。

然而好景不长,随着自动化测试的不断增加,我们会面临这样一些问题:

  1. 自动化测试是围绕着实现细节展开的。随着数量的增多,业务的轮廓很容易迷失在细节中。
  2. 在功能级别丧失了对测试的追踪。由于测试人员无法具体知晓那些测试案例被自动化测试覆盖。每次回归的时候,团队都需要回归整个测试组。

于是,我们的手动测试越来越难得到自动化测试的帮助。它开始成了项目的鸡肋。测试代码阅读困难、维护困难以及测试结果的看起来也很费劲。这直接导致了我们不仅要投入相当的时间来增加自动化测试,也要投入不少时间来阅读并利用测试结果。

于是我们开始重新审视自动化测试的做法,继续摸索更好的方式。

很快,我们发现“能够跑起来”并不是好的自动化测试仅需的特性。让我们通过一段测试代码来看一下具体怎么回事。

selenium.open(“/”)
selenium.type(“id=username”, “myname”)
selenium.type(“id=password”, “mypassword”)
selenium.click(“id=btnLogin”)
selenium.waitForPageToLoad(30000)
assertTrue(selenium.isTextPresent(“Welcome to our website!”))

这个测试中,我们首先打开了一个页面,在页面中寻找一个id为username的输入框,输入“myname”,然后再寻找一个id为password的输入框,输入“password”,然后点击一个id为btnLogin的按钮,等待30秒以后,断言页面应该出现的文字。

我们可以看到,这个测试的实现很完整的描述了测试的操作过程,是一个面向步骤而不是目的的描述。当然,稍加分析,我们也可以看出来这个测试的目的是测用户登录成功系统。

但是,想象当我们有很多这样面向步骤来描述的测试时,要从中抽离出被无数细碎的操作步骤所淹没的测试意图,并把测试的结果利用起来,其实并没有那么直观。而且,如果在测试中出现了错误,对于问题的具体功能点的定位也不是那么容易。

与此同时,并不是团队中所有的成员都有能力阅读和编写这样的测试。这无疑降低了团队成员对于自动化测试的参与度。对于客户,自动化测试更是一个黑盒子,做了什么,没做什么,基本上搞不清,更谈不上参与到自动化测试中,帮助提高测试的有效性。

种种状况,究其原因就是测试可读性太差,测试意图不够明显。可运行并且容易读的测试才是好的自动化测试。这样才能够保证任何时候,我们不会丧失对于测试案例的跟踪与管理。测试人员随时都可以通过快速阅读测试,了解那些功能已经被自动化测试覆盖,有效规划手工测试的工作量。

怎么提高测试的可读性呢?

我们的解决办法是DSL领域专用语言。

什么是领域专用语言?在马丁大叔的博客里有比较详细的描述。大致来说,领域专用语言就是针对某个领域的特定目的编程语言。不像Java、C#等通用语言,可以解决任何领域的问题。领域专用语言通过自己独特的语法结构来描述更接近于专业领域语言的业务。

让测试的描述能够接近被测系统的领域语言、使测试意图得到清晰表达就是我们想要得到的效果。DSL正好能够帮我们实现。

让我们再看看之前的那段代码:

selenium.open(“/”)
selenium.type(“id=username”, “myname”)
selenium.type(“id=password”, “mypassword”)
selenium.click(“id=btnLogin”)
selenium.waitForPageToLoad(30000)
assertTrue(selenium.isTextPresent(“Welcome to our website!”))

由于使用的是通用语言,在我们这个特定的使用场景中显得过于细节化、过程化,不能清晰表达测试意图。

换成DSL,我们的测试就可以直接用验收标准的语言来描述如下:

Given I am on login page
When I provide username and password
Then I can enter the system

这样测试的内容就直观多了,还包含了一些业务信息,让我们知道这个是在测试一个登录的场景,而不是任意的输入信息,兼顾传递了业务知识的职责。至于这些DSL背后能够运行的代码,也被隐藏起来。如果是不能够阅读原来那样的测试代码的人(不管是需求分析人员还是客户甚至一些对自动化代码关注比较少的测试人员)想要加入到自动化测试活动中进行反馈,就不会被DSL背后的代码带来的“噪音”所影响。

当然,在我们的现实应用场景中,这个需求没有那么简单,我们的验收标准还会考虑不同的数据比如输入不同组合的用户名密码:

Given I am on login page
When I provide ‘david’ and ‘davidpassword’
Then I can enter the system
Given I am on login page
When I provide ‘kate’ and ‘kate_p@ssword’
Then I can enter the system

以及更多的测试数据。

那么这种情况下,仅仅是比较通俗的语言还是不够的,毕竟测试数量在那摆着。如果测试数量不能减少,维护起来仍然很麻烦。打个比方,如果系统的实现变成了每次都要输入用户名、密码和一个随机验证码,我们就需要在我们的自动化测试中修改多处,比较繁琐。因此,我们需要在可读性比较好的自然语言描述的测试上,把它的抽象层次再提高一点。

幸运的是,我们当时选择的DSL工具是cucumber,它除了提供了几个测试的描述层次:Feature,Scenario,Steps,还提供了非常好的一种组织方式—数据表。

这样,我们的这个自动化测试就可以把之前的那个登录的功能根据特性、场景总结和具体的步骤分离开来,清晰的分层,同时利用数据表我们的测试精简成一系列被重复多次但输入数据有所变化的操作过程,如下:

Feature: authentication
In order to have personalized information
I want to access my account by providing authentication information
So that the system can know who I am
Scenario Outline: login successfully
Given I am on login page
When I provide ‘<username>’ and ‘<password>’
Then I can enter the system
Examples:
|username |password |
|david |davidpass |
|kate |kate_p@ssword|

测试这下看起来就更清爽了。首先,用Feature关键字,我们把测试分类到login这个大特性下的,并对这个特性本身的业务目的进行相关描述,带进业务目标,传递业务知识;然后用Scenario关键字来提高挈领的标明我们这个测试场景中做的是测试登录成功的情况,并且把步骤都写出来;最后,我们用Examples关键字引出具体的数据表格把用到的数据都展示出来,避免我们的相同步骤因为测试数据的变化而重复若干遍造成冗余。万一碰上了需求的变化,要求同时提供用户名、密码和验证码,那我们的测试也只需要改动较少的地方就足够了。

更棒的是,用了这种数据表的方式,整个团队的协作效率提高了。对于写代码没有那么顺畅的测试人员来说,增加自动化测试也就是增加更多测试数据,填充到数据表里就可以了。

就这样,我们用DSL实现了可执行的可读性高的文档。帮助了回归测试,降低了文档维护难度,也促进团队成员利用测试来传递知识的积极性,让更多人能够参与到测试中。如果您的团队也遇到了类似的问题,不妨也尝试一下。


本文原文发表于InfoQ:http://www.infoq.com/cn/articles/leveraging-dsl-in-agile-test

Share