测试三明治和雪鸮探索测试

测试金字塔理论被广泛应用于计划和实施敏捷软件开发所倡导的测试自动化,并且取得了令人瞩目的成就。本文尝试从产品开发的角度出发,结合Kent Beck最近提出的3X模型和近年来迅速发展的自动化测试技术,提出并讨论一种新的测试层级动态平衡观:三明治模型。同时,为了应对端到端测试在实践中面临的种种挑战,设计并实现了一种面向用户旅程的端到端自动化测试框架——雪鸮。实际项目经验表明,雪鸮能够显著提升端到端测试的可维护性,减少不确定性影响,帮助开发人员更快定位和修复问题,对特定时期的产品开发活动更具吸引力。

背景

测试金字塔

按照自动化测试的层级,从下至上依次为单元测试、集成测试和端到端测试,尽量保持数量较多的低层单元测试,以及相对较少的高层端到端测试,这就是测试金字塔理论。随着敏捷软件开发的日益普及,测试金字塔逐渐为人所知,进而得到广泛应用。Mike CohnMartin Fowler以及Mike Wacker等先后对测试金字塔进行了很好的诠释和发展,其主要观点如下:

  • 测试层级越高,运行效率就越低,进而延缓持续交付的构建-反馈循环。
  • 测试层级越高,开发复杂度就越高,如果团队能力受限,交付进度就会受到影响。
  • 端到端测试更容易遇到测试结果的不确定性问题,按照Martin Fowler的说法,这种结果不确定性的测试毫无意义。
  • 测试层级越低,测试的代码隔离性越强,越能帮助开发人员快速定位和修复问题。

3X模型

2016年起,敏捷和TDD先驱Kent Beck开始在个人Facebook主页撰写系列文章,阐述产品开发的三个阶段——Explore、Expand和Extract,以及在不同阶段中产品与工程实践之间的关系问题,即3X模型。近二十年软硬件技术的飞速发展,使得软件开发活动面临敏捷早期从未遇到的市场变革,而根据在Facebook工作的经历,Kent Beck把产品开发总结为三个阶段:

  • 探索(Explore),此时的产品开发仍处于非常初期的阶段,仍然需要花费大量时间寻找产品和市场的适配点,也是收益最低的阶段。
  • 扩张(Expand),一旦产品拥有助推器(通常意味着已经找到了市场的适配点),市场需求就会呈现指数级上升,产品本身也需要具备足够的伸缩性以满足这些需求,由此收益也会快速上升。
  • 提取(Extract),当位于该阶段时,公司通常希望最大化产品收益。但此时收益的增幅会小于扩张阶段。

(3X)

Kent Beck认为,如果以产品是否成功作为衡量依据,那么引入自动化测试在探索阶段的作用就不大,甚至会延缓产品接受市场反馈循环的速度,对产品的最终成功毫无用处,还不如不引入;当位于扩张阶段时,市场一方面要求产品更高的伸缩性,另一方面也开始要求产品保证一致的行为(例如质量需求),那么此时就该引入自动化测试来保证产品的行为一致性;当产品最终处于提取阶段时,任何改动都应以不牺牲现有行为为前提,否则由此引发的损失可能远高于改动带来的收益,此时自动化测试就扮演了非常重要的角色。

测试工具爆炸式增长和综合技能学习曲线陡升

根据SoftwareQATest网站的历史数据,2010年记录的测试工具有440个,共划分为12个大类。这个数字到2017年已经变为560个,共15个大类,且其中有340个在2010年之后才出现。也就是说,平均每年就有50个新的测试工具诞生。

面对测试工具的爆炸式增长,一方面所支持的测试类型更加完善,更加有利于在产品开发过程中保证产品的一致性;另一方面也导致针对多种测试工具组合的综合技能学习曲线不断上升。在实践中,团队也往往对如何定义相关测试的覆盖范围感到不知所措,难以真正发挥测试工具的效用,也很难对产品最终成功作出应有的贡献。

从金字塔到三明治

作为敏捷在特定时期的产物,测试金字塔并不失其合理性,甚至还对自动化测试起到了重要推广作用。但是,随着行业整体技术能力的不断提升,市场需求和竞争日趋激烈,在项目中具体实施测试金字塔时往往遭遇困难,即便借助外力强推,其质量和效果也难以度量。

此外,随着软件设计和开发技术的不断发展,低层单元测试的传统测试技术和落地,因前、后端技术栈的多样化而大相径庭;同时,在经历过覆盖率之争,如何确保单元测试的规范和有效,也成为工程质量管理的一大挑战;高层的端到端测试则基本不受技术栈频繁更替的影响,随着不同载体上driver类技术的不断成熟,其开发复杂度反而逐渐降低。

这里讨论一种新的测试层级分配策略,我们称之为三明治模型 。如下图所示,该模型允许对不同测试层级的占比进行动态调整,说明了倒金字塔形、沙漏形以及金字塔形分配对特定产品开发阶段的积极作用。

(Sandwich)

产品开发的自动化测试策略

根据3X模型,在探索初期往往选择避开自动化测试。一旦进入扩张期,产品的可伸缩性和行为一致性就成为共同目标,但此时也常会发生大的代码重构甚至重写,如果沿用测试金字塔,无论补充缺失的单元测试,还是只对新模块写单元测试,都既损害了产品的快速伸缩能力,也无法保证面向用户的产品行为一致性。因此,如果在探索后期先引入高层的端到端测试,覆盖主要用户旅程,那么扩张期内所产生的一系列改动都能够受到端到端测试的保障。

需要注意的是,用户旅程在产品即将结束探索期时通常会趋于稳定,在扩张期出现颠覆性变化的概率会逐渐减少,端到端测试的增长率会逐步下降。

除此以外,随着扩张期内不断产生的模块重构和服务化,团队还应增加单元测试和集成测试的占比。其中,单元测试应确保覆盖分支场景(可以在CI中引入基于模块的覆盖率检测);集成测试和某些团队实践的验收测试,则需进一步覆盖集成条件和验收条件(在story sign-off和code review时验收)。

许多新兴的测试技术和工具擅长各自场景下的验收测试,但更重要的仍是识别产品阶段和当前需求,以满足收益最大化。

(Sandwich-3x)

由此我们认为,随着产品开发的演进,测试层级的分配应参考三明治模型,动态调整层级占比,更加重视运营和市场反馈,致力于真正帮助产品走向成功。

端到端测试的机遇和挑战

与其他测试层级相比,端到端测试技术的发展程度相对滞后。一方面,作为其基础的driver工具要在相应载体成熟一段时间之后才能趋于稳定,web、mobile无不如是。另一方面,端到端测试偏向黑盒测试,更加侧重描述用户交互和业务功能,寻求硬核技术突破的难度较高,于是较少受开发人员青睐。但是,由于端到端测试更接近真实用户,其在特定产品开发活动中的性价比较高,有一定的发展潜力。

然而,当前实践中的端到端测试,普遍存在如下问题:

  • 低可维护性。一般实践并不对测试代码质量作特别要求,而这点在端到端测试就体现得更糟。因为其涉及数据、载体、交互、功能、参照(oracle)等远比单元测试复杂的broad stack。虽然也有Page Object等模式的广泛应用,但仍难以应对快速变化。
  • 低运行效率。如果拿单次端到端测试与单元测试相比,前者的运行效率肯定更低。因此只一味增加端到端测试肯定会损害构建-反馈循环,进而影响持续交付。
  • 高不确定性。同样因为broad stack的问题,端到端测试有更高的几率产生不确定测试,表现为测试结果呈随机性成功/失败,进一步降低运行效率,使得真正的问题很容易被掩盖,团队也逐渐丧失对端到端测试的信心。
  • 难以定位问题根因。端到端测试结果很难触及代码级别的错误,这就需要额外人工恢复测试环境并尝试进行问题重现。其中所涉及的数据重建、用户交互等会耗费可观的成本。

方法

为了解决传统端到端测试遇到的种种挑战,本文设计了一种面向用户旅程的端到端自动化测试框架——雪鸮(snowy_owl),通过用户旅程优先、数据分离、业务复用和状态持久化等方法,显著提高了端到端测试的可维护性,降低不确定性的影响,并且能够帮助团队成员快速定位问题。

用户旅程驱动

端到端测试应尽量贴近用户,从用户旅程出发能保证这一点。在雪鸮中,用户旅程使用被称作play books的若干yaml格式的文件进行组织,例如下列目录结构:

play_books/
  core_journey.yml
  external_integration.yml
  online_payment.yml

其中每个play book由若干plots所组成,plot用于表示用户旅程中的“情节”单位,其基本特征如下:

  • 单一plot可以作为端到端测试独立运行,例如发送一条tweet的情节:
SnowyOwl::Plots.write 'send a plain text tweet' do
  visit '/login'  
  page.fill_in 'username', with: 'username'
  page.fill_in 'password', with: 'password'
  page.find('a', text: 'Sign In').click
  # verify already login?
  page.find('a', text: 'Home').click
  # verify already on home page?
  page.fill_in 'textarea', with: 'Hello World'
  page.find('a', text: 'Send').click
  # verify already sent?
end
  • 单一plot应是紧密关联的一组用户交互,并且具备体现一个较小业务价值的测试参照。
  • plot可以被play book引用任意次从而组成用户旅程,play book同时定义了所引用plots之间的顺序关系,基本语法如下所示:
---
- plot_name: send a plain text tweet
  digest: 2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
  parent: d6b0d82cea4269b51572b8fab43adcee9fc3cf9a

其中plot_name表示情节的标题,digest和parent分别表示当前情节引用在整个端到端测试过程中的唯一标识和前序情节标识,初期开发人员可以通过各个情节的引用顺序定义用户旅程,大多数情况下digest和parent将由系统自动生成并维护。

整个play books集合将是一个以plots为基础组成的森林结构,而端到端测试的执行顺序则是针对其中每棵树进行深度遍历。

通用业务复用

由于plot本身必须是一个独立可运行的端到端测试,那么plots之间通常会共享一部分交互操作,例如用户登录。雪鸮允许把高度可复用的交互代码进行二次抽取,称作determination:

SnowyOwl::Determinations.determine('user login') do |name, user_profile|
  # return if already login
  visit '/login'  
  page.fill_in 'username', with: user_profile[:username]
  page.fill_in 'password', with: user_profile[:password]
  page.find('a', text: 'Sign In').click
  # verify already login?
end

这样,plot的代码就可以简化成:

SnowyOwl::Plots.write 'send a plain text tweet' do
  determine_user_login({username: 'username', password: 'password'})
  page.find('a', text: 'Home').click
  # verify already on home page?
  page.fill_in 'textarea', with: 'Hello World'
  page.find('a', text: 'Send').click
  # verify already sent?
end

这里应注意Determination和Page Object的区别。看似使用Page Object可以达到相同的目的,但是后者与Page这一概念强绑定。而Determination更加侧重描述业务本身,更符合对用户旅程的描述,因此比Page Object在plot中更具适用性。当然,在描述更低层的组件交互时,Page Object仍然是最佳选择。

测试数据分离

合理的数据设计对描绘用户旅程非常重要,雪鸮对测试逻辑和数据进行了进一步分离。例如用户基本数据(profile),同样是使用yaml文件进行表示:

data/
  tweets/
    plain_text.yml
  users/
    plain_user.yml

那么在plot的实现中,就可以使用同名对象方法替代字面值:

SnowyOwl::Plots.write 'send a plain text tweet' do
  determine_user_login({username: plain_user.username, password: plain_user.password})
  page.find('a', text: 'Home').click
  # verify already on home page?
  page.fill_in 'textarea', with: plain_text.value
  page.find('a', text: 'Send').click
  # verify already sent?
end

情节状态持久化

雪鸮的另一个重要功能是情节状态的持久化和场景复原。为了启用情节状态持久化,开发人员需要自己实现一个持久化脚本,例如对当前数据库进行dump,并按照雪鸮提供的持久化接口把dump文件存储至指定位置。

当端到端测试运行每进入一个新的情节之前,系统会自动执行持久化脚本。也就是说,雪鸮支持保存每个情节的前置运行状态。

当端到端测试需要从特定的情节重新开始运行时,雪鸮同样会提供一个恢复接口,通过用户自定义的数据恢复脚本把指定位置的dump文件恢复至当前系统。

该功能有两处消费场景:

  • 由于broad stack的问题,端到端测试不确定性的技术因素一般较为复杂。实际经验表明,测试的随机失败率越低,就越难以定位和修复问题,而通过不断改进测试代码的方式消除这种不确定性的成本较高,效果也不好。但是,可以尽量消除不确定性带来的影响。例如,不确定测试导致的测试失败,通常会导致额外人工验证时间,完全可以选择让系统自动重试失败的测试。另一方面,重试会造成测试运行效率降低,特别是针对端到端测试。当一轮端到端测试结束后,雪鸮只会自动重试失败的情节测试,同时利用该情节对应的数据dump文件保证场景一致性,这就减少了重试整个端到端测试带来的运行效率下降问题。
  • 当团队成员发现端到端测试失败,通常需要在本地复现该问题。而借助测试dump文件,可以直接运行指定plot测试,从而避免额外的人工设置数据和交互操作,加快问题定位和解决。

实践

雪鸮在笔者所在的项目有超过6个月的应用时间。该项目在产品开发方面长期陷入困境,例如过程中同时兼具了3X每个阶段的特点,不仅缺少清晰的产品主线,还背负了接棒遗留系统的包袱。这种状况对工程质量管理提出了更大挑战。

项目采用雪鸮对已有端到端测试进行了重构,生成了一个核心用户旅程和三个涉及外部系统集成的重要用户旅程,包含24个plots,9个determinations,使端到端测试实现了长期稳定运行。在本地相同软硬件环境下,不确定性导致的随机失败从原有10%降低至1%以内,部署至云环境并采用headless模式后,连续15天测试失败记录为零,运行效率的损失可以忽略不计。同时,当用户旅程产生新分支时,可以引入新的情节测试节点,并且根据业务需求将其加入现有play book树,从而实现端到端测试的快速维护。

持续集成与常态化运行

项目完整的端到端测试的平均运行时间保持在19分钟左右,为了不影响现有持续集成节奏,CI每30分钟自动更新代码并运行端到端测试,结果在dashboard同步显示,一旦发生测试失败,第一优先级查找失败原因并尝试在本地复现和修复。

常态化运行端到端测试的另一个好处是,能够以低成本的方式实现24小时监控系统各个组件的功能正确性,有助于更早发现问题:一次,产品即将上线的支付功能发生异常,查看CI记录发现端到端测试在晚上9:15左右出现了首次告警。通过及时沟通,确认是海外团队在当时擅自改动了支付网关的一个配置,造成服务不可用的问题,并迅速解决。

结论与展望

Kent Beck的3X模型,提出了从不同产品开发阶段看待工程实践的新视角。而敏捷一贯推崇的TDD等实践,更多体现在个人技术专长(Expertise)方面,与产品是否成功并无必然联系。然而,程序员的专业主义(Professionalism)的确同时涵盖了技术专长和产品成功两个方面,二者相辅相成。因此,如何通过平衡众多因素并最终提高整体专业性,这才是软件工程面临的经典问题。本文给出的测试三明治模型,目的就是帮助思考产品开发过程中测试层级间的平衡问题。

为了应对现有端到端测试面临的挑战,本文设计并实现了一种新的面向用户旅程的端到端测试框架,通过职责隔离、业务复用和状态持久化等手段,构建了易于维护且更加有效的端到端测试。同时,基于上述方法构建的测试代码,更易于和自动化测试的其他研究领域相结合,在诸如测试数据构建、用例生成、随机测试和测试参照增强等方向有进一步的应用潜力。


更多精彩洞见,请关注微信公众号:思特沃克

Share

浅谈移动应用的技术选型

在这个巨变的时代,技术选型是个很难做决定的事情,而移动应用技术领域在几个巨头(Google,Facebook,Apple etc.)的带动下更是日新月异。所以说要选择一个适合业务需求并且匹配开发人员能力的技术方案并不是一件简单的事情。我也只是在移动开发上做过一点微小的工作,此处仅能抛个砖,希望各位有玉的大神尽管砸过来。

做移动应用开发,说起来技术方案不外乎HTML5(没错,做Mobile Web其实也算是一种移动应用)、Native(在Android上不管是用Java、Kotlin还是Scala,iOS上不管是用Objective-C还是Swift)和使用原生UI,用JavaScript来实现逻辑的诸如React Native一类的方案。除此之外,还有结合HTML5和Native的Hybird混合方案。不同的技术方案有着不同的适应场景,至于具体如何选择,接下来我简单地谈谈自己的理解。

1、HTML5

也就是Web App的方案。这种方案最大的优点在于“Write Once, Run Everywhere”,不管你是Android还是iOS,都可以用一套代码搞定,在国内的话还能对接微信公众号,给用户提供一个方便快捷的入口,并且还有版本升级容易的优势(毕竟服务器是受自己控制的)。但是这种方案的缺点也很明显——无法使用系统级API,只能做为一个临时的入口,用户很难留存,并且因为浏览器性能的原因,很难带来很好的用户体验。

所以说Web App的主要适用场景还是在于作为对非核心业务在移动端的入口补足,或者是作为用户轻量、低频使用的体验增强。

1-meituan_guide

美团移动网站引导页

2-meituan_home

美团移动网站首页

美团的移动网页就是很典型的例子,主要还是提供给不经常使用的用户一个入口,网站内部还是在尽量引导用户下载使用客户端。

2、Hybird

Hybird是一种兼顾Native与HTML的开发模式,但根据实现的不同,还可以再细分为两种实现方案:

  • 在Native App中使用WebView加载远端Web资源
  • 使用Cordova/PhoneGap等框架通过WebView加载本地资源进行页面渲染

第一种方案其实已经应用得非常普遍了,很多应用的展示页面都是通过这种方式实现的。因为展示页面需要的正是能够轻易更换内容及布局的格式,并且这种纯展示的页面也并不需要复杂的动画与特效,使用Web页面是一个非常合适的解决方案。

而第二种方案前一段时间非常火,因为它在跨平台,在高效开发以及快速发布上有着明显的优势,毕竟Web内容只需要开发一次就可以在各个平台使用。而且将资源打包到本地也可以在一定程度上缓解从远端加载静态资源导致UI展示延迟的问题,并且还可以通过桥接Native和Web来调用一些Device的API。但其劣势也很明显,一是通过WebView执行代码效率较低,很难实现一些炫酷的效果,并且还存在不同设备的兼容性问题;二是如果想调用相关平台的API,需要针对平台单独进行开发,如果在应用中用到了大量的Device API,那么开发的效率将大大降低;三是很难应用到平台相关的新特性,比较难做出有特色的产品。

使用HTML页面来实现纯展示页面是非常推荐的一种方案。而Cordova/PhoneGap则更适用于对Mobile预算有限的公司、创业团队,或者对App进行快速的上线验证。

正好之前有个项目就用到了这种方案,为一家业务转型的零售商提供了使用一套基本代码来完成Android和iOS两个平台的App和微信公众号的相关页面的技术方案。3-jingbao_app4-jingbao

零售商Android应用零售商微信端

3、React Native

把React Native单独拿出来,是因为确实不能简单的将它分到其它任意一种方案里面去。React Native确实是最近最火的跨平台App解决方案了。它脱胎于React,因为React基于Virtual DOM来进行界面渲染,所以用Native的View来替换掉原本React的HTML DOM就顺理成章的引出了React Native的概念。

它与之前的跨平台方案有一个本质的区别,在于:其它方案都在追求写一次code解决所有平台的问题,而React Native的理念在于“Learn Once, Write Anywhere”。虽然大部分代码是平台无关的,但是平台相关的代码都需要单独实现,这虽然对跨平台带来了不便,但是引入的好处也是显而易见的,View层的部分通过原生组件实现,性能比其他WebView的方案不知道高到哪去了。而且React Native整套的逻辑代码都通过JavaScript实现,这样就让跨平台应用能够方便的复用逻辑代码。另外虽然React Native没有支持使用CSS来实现样式,但是提供了类似CSS的样式表支持,有过UI开发经验的人都能够非常快的上手。由于前端React也是非常的火,很多React社区的很多产出都可以在React Native上借鉴使用。

React Native对于没有复杂动画效果的一般应用来说不失为一个很好的解决方案。而且对于一些小型的企业级应用也是非常适用的。但是,React Native对于Android平台的支持度是不如iOS平台的,而且现有的非常成熟的应用也较少,所以说如果要在一些面向用户量很大,讲求用户体验的App中使用还是要慎重考虑的。

但是,其实Facebook已经在自家的App上用起来了,而且实测效果还是很好的。不过呢,人家毕竟是自家维护的,所以说真正要在项目上用可能还是得试了才知道效果。

5-facebook6-facebook_ios

facebook Androidfacebook iOS

4、原生应用

原生应用的开发真的是让人又爱又恨。爱在于你可以在它上面施展拳脚、使用新特性、实现炫酷的效果。而恨则在于它跨平台性几乎为零,除了资源外几乎没有可重用的东西,即使是相似架构上的逻辑你也得再实现一遍。使用原生开发,能够方便地添加动画效果,调用底层硬件,所有的限制仅仅是来自平台的限制。但是正常情况下需要对不同的平台搭配不同的开发人员,而且如果要追求良好的用户体验,整个应用的设计还得满足相应平台的设计规范,这不仅是对Dev的考验,也是对UX的考验。不过如果真的对App的质量有很高的要求,我觉得这一切的付出也还是都是值得的。

如果针对的是要求硬件性能、讲究动画效果、追求用户体验的应用,还是建议分平台单独设计,并且都使用原生的技术方案来实现。其实这也是目前市面上大部分企业做出的选择。

使用原生开发我个人还有一个观点,就是设计上要尽量遵守原生应用的设计规范,如果想要一套设计通吃所有平台,最终只会搞一个不伦不类的应用出来。知乎算是国内在这方面做得比较好的应用了,也取得了不错的效果。

7-zhihu

知乎

其实,在真正启动项目之前,在进行技术选型时,除了要考虑更符合业务的架构外,还要考虑开发人员的能力及技术栈。毕竟最后App还是由Dev们开发的。如果仅仅考虑业务而不考虑开发人员的技术能力来选择技术方案,不仅有一种钦定的感觉,而且最后往往坑到的还是自己。

我们常说:工具是死的,人是活的。考虑多种因素,在技术选型上做出更充分的考量,才是真正正确的选择。所以说又回到那句老话上:“It depends…”

Share

移动App测试的22条军规之“确定设备和平台再动手”

(ThoughtWorks洞见网站 获人民邮电出版社和作者授权连载本书部分章节。任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。)

第一章

1军规:确定设备和平台再

在测试设计之初, 测试人员首先会考虑的是什么呢?没错,就是测试的环境,也就是确定app究竟需要运行在什么样的设备和平台上。

显然,在移动设备和平台碎片化的现实中,测试人员穷尽所有设备和操作系统的版本来实现全覆盖的测试是不可能的。那如何在有限的时间和精力投入下,从投入产出比的角度出发,达到尽可能多的测试覆盖呢?这里主要考虑以下几个方面:

  1. app的特性
    1. 如果app是针对心率监测,指纹识别,NFC(近场通信),红外线操控这些需要特殊传感器设计的,那对测试设备和平台的选择就相对少一些,只需要考虑那些拥有这些传感器的设备。 例如对于支持指纹识别的app,测试人员需要考虑的设备也就是iPhone 5siPhone 6iPhone 6PlusiPad Air2iPad mini3LG G3,三星Galaxy S5,三星Galaxy Note4HTC One Max,华为Mate7这些设备(不考虑市场占有率比较低的vivoOPPO的手机);而如果app支持心率监测, 测试人员就只能选择三星Galaxy S5Galaxy Note4了。

里推荐大家使用一个网站http://www.phonearena.com来做设备的查找工作。通过这个网站不仅可以查询到各种手机和平板设备的详细参数信息,还可以对它们进行横向对比,方便测试人员找到适合用来做测试的设备(如图1.1)。

样章-1

1.1 http://www.phonearena.com设备对比

    1. 如果app是针对某种平台所独有的功能设计的,或者是某种平台独占的,测试人员就只需要考虑相应平台下的设备。比如app是类似Android设备上层出不穷的“xx清理大师”,那在确定测试设备和平台时就不需要考虑iOS平台了;又比如之前Instagram选择只支持iOS平台,那作为Instagram的测试人员只需要关注与iOS设备就足够了。

或者,如果app选择不支持某种平台,相应地,测试人员也就不需要测试运行这些平台的设备了。比如WindowsPhone、黑莓BlackBerry以及塞班Symbian平台在市场上的占有率已经很低了(根据2014年第四季度的调查,详见图1.2),如果在开发时选择不支持这些平台,那在测试时测试人员就完全可以忽略相关的设备。

样章-2

1.2 2014年第四季度各操作系统市场占有率调查表数据来源: www.netmarketshare.com

    1. 如果app是面向大众的通用型app,测试人员就需要结合移动app的生命周期和测试设备的硬件参数来确定测试设备和平台了。
  1. app的生命周期
    1. 对于还处于开发阶段但准备不久之后投入市场的一款新app,鉴于并没有已经实际使用app 的用户,所以测试人员要“预测”真实的用户所使用的设备和平台。在这种情况下,首先需要了解使用app的主要用户是哪一类人群,比如说是发烧友,还是商务人士 。发烧友极有可能使用的是最新的设备和平台;商务人士更多使用的是成熟的平台,高端一些的设备;而如果用户是普通大众,就需要通过 AppleGoogle官方布的版本占有率数据来帮助测试人员进行有依据的“拍脑袋”了。

以下是Apple官方布的iOS版本占有率数据(如图1.3: https://developer.apple.com/support/appstore/ Google官方布的Android版本占有率数据(如图1.4: http://developer.android.com/about/dashboards/index.html

样章-3

1.3 - 截止201515日,iOS各版本所占比例

样章-4

1.4 - 截止201515日,Android各版本所占比例

    1. 对于已经发布并且有稳定用户群的app,测试人员可以使用在桌面应用开发时用到的工具,例如Google AnalyticsOmniture SiteCatalyst(现在Omniture Adobe收购了,工具也改名叫做Adobe Analytics )来统计的信息,从而确定app支持和需要测试的设备及平台。这里对于app有一点要求,就是app需要联网对后台的服务器发送请求,从而能获取到用户信息。

Google AnalyticsGoogle分析,http://www.google.com/analytics )是Google的一款免费的网站分析服务,使用范围也很广泛。Google Analytics功能非常强大,只要在网站的页面上加入一段代码,就可以提供的丰富详尽的图表式报告。Google Analytics的特点是简单易用,但是相应的缺点就是不可定制化。

样章-5

1.5 Google Analytics

Omniture SiteCatalystAdobe Analytics http://www.adobe.com/solutions/digital-analytics.html )是一个进行网站基本指标的搜集,报告和分析工具。由此通过这个软件可以得到网站和app的访问量,浏览量,跳出率,转化率,来源等诸多指标。只要在app中对不同事件以及发送请求都添加相应的Omniture追踪,然后再登陆Omniture的网页就可以进行用户数据分析。Omniture SiteCatalyst不同于Google Analytics的一个特点是,它可以对数据进行高级细分,也就是说,可以对用户的各种操作打上不同的标签,在服务器端搜集到信息后进行统一的筛选和分析。

样章-6

1.6 Omniture SiteCatalyst

    1. 对于上面两种情况,有一种特例需要考虑,就是在有新的操作系统版本将要发布的时候,需要参考以前操作系统版本升级时用户更新的进度。正如图1.31.4所示,在 iOS 8发布三个月之内有68%的用户进行了升级,而使用iOS 7之前版本的用户只有4%;而Android 4.4 Kitkat发布一年后,市场占有率才刚刚达到39.1%,有超过52.7%的用户使用的还是4.04.3版本的Android,甚至还有8.2%左右的用户还在使用着Android 2.x的设备。

根据这些数据,测试人员在iOS操作系统版本升级时需要及早适配新的app版本;而对于Android发布新的操作系统时,测试人员主要还得关注当前市场占有率高的那些老版本。

  1. 设备的硬件参数
    1. 屏幕尺寸:现在手机越出越大,连坚持自己风格的Apple也开始跟风发布大屏手机了。屏幕大小除了会影响显示效果外,还会影响到用户的使用习惯。一般用户手持6寸屏幕的设备时,会采取双手操作的方式,所以app如果同时支持横纵屏显示会带来更好的用户体验(如图1.7所示)。
    2. 样章-7

1.7 - 双手持握设备的方式

而对于45寸这种可以单手持握的设备,如果app无论横纵向显示,按钮都最好不要放在屏幕四个角,以免用户很难点击(如图1.8所示)。

样章-8

1.8 单手操作范围。

49%的单手操作用户采用的是以上两种姿势(左手用户相反)。绿色代表容易点击区域,黄色为拇指伸展可到点击区域,红色区域超出单手可点击范围

    1. 分辨率:分辨率的大小会决定显示内容的多少,这对显示图片和视频时会有一定的影响(如图1.9所示)。样章-9

1.9 - 不同分辨率下显示内容的大小以及显示比例

还需要注意的是,有些厂商(比如说魅族)虽然标注的屏幕尺寸和通用产品一致,但由于显示比例的不同,分辨率和通用产品也会有差别(如图1.10所示魅族MX4采用的是15:9的屏幕比例,而非标准的16:9的屏幕比例)。

样章-10

1.10 魅族MX4的的屏幕比例

    1. 像素密度:屏幕大小和分辨率决定了像素密度。不同的像素密度对于显示也会有差别:在retina的屏幕上显示非retina的图片会很模糊,反之则会显得失真(如图1.11和图1.12所示)。如果需要同时支持retina和非retina的设备,那测试人员需要测试是否对图片尤其是app的显示图片提供retina和非retina两个版本的图片。样章-11

1.11 retinaretina的文字显示

样章-12

1.12 -非retinaretina的图片显示

选取了操作系统版本和测试设备之后,就可以设计矩阵来配对操作系统版本和测试设备了。具体可以参考图1.13的表格。

样章-13

1.13 - 测试设备和操作系统版本对照表

设计测试设备和操作系统版本对照表的原则是:让不同分辨率,不同屏幕尺寸大小的设备尽可能多地涵盖各个操作系统版本,另外,对于市场占有率很高的重点操作系统版本,可以使用多个设备来测试。

可以看到,对于同一种设备(图1.13中的iPhone 5s),由于市场占有率大,而且支持多个操作系统版本,所以在iPhone 5s上需要测试iOS 7.18.1这两个版本;由于iPhone 5siPhone 6Plus分辨率、性能等都不一样,所以同样对于iOS 8.1,两者都需要测试。

在设计Android设备和操作系统的覆盖时,可以看到对于类似的设备(HTC One XL和三星Galaxy S3硬件水平很接近),并没有要在它们上分别都测试覆盖Android 4.14.2,而是在HTC One XL测试Android 4.1,在三星Galaxy S3上测试Android 4.2Sony Xperia Z不仅在CPU、内存、屏幕大小和分辨率上都和三星Galaxy S3不同,所以在这两部设备上都需要测试Android 4.2

设计表格的过程中,测试人员还需要注意两点:

  1. 操作系的小版本升一般只是修复缺陷,不会引入新的功能,例如iOS8.0.1升级到8.0.2,以及Android4.4.1升级到4.4.4。这时,如果不是app恰好被这些缺陷修复所影响,测试人员不需要考虑覆盖这些小版本。至于中间版本的升级,例如从iOS 8.0.2升级到8.1,以及Android4.1升级到4.4,这时需要考察变动对app的影响,决定是否测试覆盖相应版本。就拿Android 4.14.4来说,因为Android 4.44.1新增了ART运行环境,所以针对这一点,测试人员需要准备设备安装Android 4.4,而不是仅仅在安装有Android 4.1的设备上测试。至于操作系统大的版本升级,就必须要进行测试覆盖了。
  1. 随着操作系统升级,既有的设备可能无法流畅地运行新的操作系统时,测试人员就需要考虑是不是还继续在新的操作系统上测试这些设备。比如,iPhone 4在升级iOS 7之后运行速度变得很慢,各种操作的延迟都会很长,固然有一部分用户还是强忍着会继续使用,但是很多用户会放弃在新的操作系统上使用运行很慢的老旧设备。当新的操作系统升级时,甚至有些旧的设备就不会被支持了,例如iOS 8就不再支持iPhone 4 。这时候如果确定这些旧的设备上的操作系统占比很小的话,测试人员就可以果断放弃这些设备。

所以测试人员需要从设备角度出发决定要测试的操作系统,以及从操作系统出发决定要测试的设备这两方面来考虑测试设备和操作系统版本对照表的制定。

明确了测试设备和操作系统版本,下面我们就来了解下在设计测试场景和用例中可以运用哪些具体的军规。

购买本书请点击链接:http://item.jd.com/11730286.html

Share

BDD在移动开发中的应用

bdd

内容转自:文章作者来自:Prateek Baheti&Vishnu Karthik,图片来自网络。

Prateek Baheti是ThoughtWorks的开发人员,他做了两年Twist的开发。除了写代码,他还喜欢驾驶,听音乐,看板球比赛,打乒乓球。

Vishnu Karthik是ThoughtWorks的开发人员,他一直从事Twist的开发和测试自动化。之前他在比哈尔(印度东北部一座城市)的医疗保健服务中心工作。除了写代码,他还喜欢玩极限飞盘。

移动应用程序现在已经非常普及,大多数的应用可以支持3种主流平台:iOS、Android和Windows phones。此外Firefox OS平台的市场占有率也在不断提升中。

应用程序的功能是与平台无关的。但是不同的平台还是会有差异,例如处理消息事件的方式等。测试移动应用程序,并保证它们能在所有的平台上正常工作,是一项很有挑战的工作。我们需要为不同的平台编写不同的测试用例并且分别执行。这样就会导致各个平台上的测试覆盖率不一样,而且测试用例也会变得原来越难维护。平台级别的差异实际上和应用程序的功能是无关的,所以理想的中的测试用例应该纯粹使用业务语言进行描述。

行为驱动开发(BDD)风格的测试可以极大地改善这种情况。

为什么使用BDD?

BDD风格的测试用例使用纯业务领域的语言进行描述。这种方式提供了一种更好的理解测试用例的途径。测试用例使用了高层次的逻辑表述,而不会包含具体的实现细节(例如点击一个按钮)。

BDD方法有很多工具的支持,这些工具可以把测试案例规范和底层实现细节关联起来。这种风格的测试已经被证明是易于维护的,也易于描述测试用例。

针对移动应用程序,BDD可以在以下方面提供帮助:

1. 对底层细节进行抽象并提供高层次的步骤(steps):

BDD对底层细节进行抽象,并提供高层次的测试用例步骤,这样就会与平台无关了。下面来看一个发短信的应用程序的测试场景。这个测试使用Twist编写而成。

上面的测试不涉及任何的底层实现,而是使用了平台无关的语言,用业务术语描述测试场景。在这个测试用例中,接收消息提示是一个业务上的术语,对它的实现将会针对平台而不同。

2. 因此这种测试用例可以被不同平台和团队使用:

会有一个通用的接口来负责和不同的实现进行交互。

public interface MessagingDriver {
  void login(String userName);
  void sendMessage(String toAddress, String message);
  void checkForNotifications(String address);
}

现在每个平台可以有特定的实现了:

public class AndroidMessagingDriverimplements MessagingDriver {
  public void login(String userName) {
  // login for android
  }
  public void sendMessage(String toAddress,String message) {
  // send message for android
  }
  public void checkForNotifications(Stringaddress) {
  // check for notification for android
  }
}

可以使用环境变量在运行时切换到不同的平台实现上。

public class MessagingDriverFactory {
  public static MessagingDrivergetMessagingDriver() {
    String testPlatform =System.getenv("TEST_PLATFORM");
    if (testPlatform.equals("android")) {
      return new AndroidMessagingDriver();
    } else if (testPlatform.equals("ios")) {
      return new IOSMessagingDriver();
    }
    throw new RuntimeException("Failed to find animplementation");
  }
}

这样,测试实现仅仅需要去使用工厂模式和事先设置好的合适的环境变量,测试运行的时候会自动匹配相对应的平台驱动。

测试数据和测试场景不再需要重复,它们被视作一个可以执行的文档,从而共享给同一个应用的不同平台的团队

Share