美团团队---客户端自动化测试研究

测试做为质量保证极其重要的一环,在移动App开发流程中起到很是关键的做用。从开发工程师到测试工程师,人人都应具有良好的测试意识,将隐患和风险在上线以前找出并解决,能够有效的减小线上事故。html

美团和大众点评App做为美团点评平台的主要入口,支持承载着美团点评各大业务。其中美团点评境外度假业务主要包括了出境游相关业务以及全部的境外城市站,也是美团点评很是看重和大力发展的业务线。为了保证质量,须要进行各项测试:冒烟测试[1]、功能测试、集成测试、专项性能测试,回归测试[2]。其中冒烟测试和回归测试大多由开发本身手动执行,有较大的优化空间。一方面,测试的人力成本较高;另外一方面,在以前的测试过程当中发生过漏测等问题,这些问题在测试阶段被QA发现,又会再次返工,费时费力。android

鉴于这两部分测试用例相对稳定,不会频繁发生较大的变化,咱们打算将其自动化,下降人力成本投入,将测试结果报表化,避免人为疏漏形成的一系列问题。ios

[1]冒烟测试(smoke testing),就是开发人员在我的版本的软件上执行目前的冒烟测试项目,肯定新的程序代码不出故障。冒烟测试的对象是每个新编译的须要正式测试的软件版本,目的是确认软件基本功能正常,能够进行后续的正式测试工做。冒烟测试的执行者是版本编译人员。 [2]回归测试是软件测试的一种,旨在检验软件原有功能在修改后是否保持完整。nginx

目前业界测试方案很是多,Android和iOS双平台的方案加起来大约有十七八种。应该如何选择适合团队的测试方案呢?咱们主要考虑如下几个方面:git

  • 平台支持。
  • 稳定性。
  • 维护成本。
  • 可扩展性。

其中维护成本咱们尤其看重。目前团队的开发和测试同窗任务都比较饱和,业务处于高速发展期,无法抽出太多的时间开发/维护测试脚本,这就须要在这方面作到在投入较少时间的前提下不影响自动化测试的结果产出。常规的TDD[3]是函数级别进行测试驱动开发,一般须要在代码级别作不少工做,须要测试团队投入较大的开发成本。鉴于在成本方面的考虑,咱们打算使用BDD[4]来解决这个问题。主要在行为层面进行测试投入,在代码层级方面投入较小,用很是有辨识力的行为进行测试。程序员

在平台支持方面,因为是客户端团队,因此咱们但愿写好的用例能够同时跑在Android和iOS两个平台上,还但愿用例能够一部分进行美团和大众点评两个App的复用,因此须要一个能够跨平台的方案。github

[3]测试驱动开发(Test-driven development,缩写为TDD)是一种软件开发过程当中的应用方法,倡导先写测试程序,而后编码实现其功能得名。测试驱动开发是戴两顶帽子思考的开发方式:先戴上实现功能的帽子,在测试的辅助下,快速实现其功能;再戴上重构的帽子,在测试的保护下,经过去除冗余的代码,提升代码质量。 [4]行为驱动开发(Behavior-driven development,缩写BDD)是一种敏捷软件开发的技术。它经过用天然语言书写非程序员可读的测试用例扩展了测试驱动开发方法。算法

去年年末的时候咱们团队就自动化测试方面进行了探索。发现Calabash知足BDD和跨平台,因而进行了小范围试用。在脚本开发和维护方面,成本确实低于函数级别的测试开发,它能够用一种相似天然语言的方式编写测试用例,这是一个简单的test case示例:sql

Scenario: 首页
    Then I press "上海"
    When I press view with id "city" Then I see "海外" When I press "海外" And I press view with id "start_search" When I enter "东京" into input field number 1 Then I press list item number 1 Then I see "东京" When I press "美食" ... 

这个示例相信开发工程师们甚至没写过代码的人也看得懂,其实就是用常规的行为思惟模式去编写测试用例。其中Feature、Scenario、Step是BDD的三个核心概念:ruby

  • Feature:就是字面意思,主要是描述功能特性。
  • Scenario:场景,在这里能够简单的理解为一个个的细分case,一般状况下须要多个场景拼接来完成一个具体的test case。
  • Step:实现场景的步骤代码。

可是Calabash在业内相对小众,遇到问题就不太好解决。好比在某些三星手机上就遇到了某些控件根据ID找不到的问题,会影响UI元素的定位。在编写自动化脚本时,元素定位的惟一性是一个看似简单实际上会有不少坑的问题,脚本的稳定性必定程度上依赖了如何进行元素定位。

其次,在Android团队想要把方案推广到iOS平台的时候,咱们发现了一个很大的问题:iOS接入Calabash的成本过高。Android的接入成本很低,只须要一个重签名的apk文件就能够了,并不依赖源码,而iOS的接入须要依赖源码作一些工做,这就给iOS同窗形成了不少困难。美团和大众点评是两个巨大的App,在源码接入方面的工做量并不小,并且不少隐患没法预料,就算依赖源码接入以后,还有一个问题须要解决:iOS的ID系统。一般iOS业务开发代码中不是经过ID来获取页面元素,无论是手写布局代码仍是用xib布局,开发者通常不会给界面元素加ID,因此iOS的元素大多都没有ID,而Calabash对元素的定位主要依赖ID,这无疑让咱们感到雪上加霜。

在Android团队用写好的用例进行了几个版本的冒烟测试以后,团队内部Android、iOS、QA的同窗坐下来一块儿进行了方案后续的探究,最终决定放弃Calabash,继续寻找能够替代的方案。

在经历过Calabash的挫折以后,咱们在选型方面更加慎重。QA同窗对Appium有必定的经验,因而先采用了Appium方案进行兼容性测试和部分回归测试。在业务快速发展的过程当中,维护成本让QA同窗愈来愈疲于应付,因而咱们又坐在一块儿进行新方案的讨论和探索。

Calabash的BDD模式是你们承认的,也是你们愿意接受的,那就须要在新的方案中,继续使用这种方式编写维护测试用例。咱们想把Appium和Calabash二者的优点结合起来,还想把以前写过的Calabash的测试用例无缝迁移继续使用。

取其精华

Calabash为何可使用相似天然语言的方式编写测试用例达到BDD的效果呢?根本缘由是由于Cucumber

在Calabash官网中注明了他们使用了Cucumber(一种简单的天然语言方式的BDD开源解决方案),那么咱们可否底层使用Appium支持,上层使用Cucumber进行测试用例的开发和维护呢?

答案固然是可行的。咱们在Appium的官方示例代码中找到了答案。Appium官方提供了与Cucumber结合使用的例子做为参考,虽然这部分代码已经两年没更新了,可是依然给咱们提供了关键思路。

新方案造成

客户端的同窗与QA同窗进行了讨论,确认了使用QA同窗目前使用的按照App进行用例拆分的方案。以前Calabash的方案有不少能够借鉴过来,因而咱们先进行了总体结构的调整:

按照点评和美团两个App进行用例区分,公共步骤的封装在common_steps.rb中。点评和美团的目录下分别有cucumber.yml脚本,这是用来区分Android和iOS平台的,内容大概是这样:

# config/cucumber.yml ##YAML Template --- ios: IDEVICENAME='ios' android: IDEVICENAME='android' 

其中Android/configiOS/config是Android和iOS两个平台的特定配置,这部分配置代码在support包内,是Appium启动须要加载的配置。

平台的区分在env.rb中体现出来:

class AppiumWorld end if ENV['IDEVICENAME']=='android' caps = Appium.load_appium_txt file: File.expand_path("./../android/appium.txt", __FILE__), verbose: true elsif ENV['IDEVICENAME']=='ios' caps = Appium.load_appium_txt file: File.expand_path("./../ios/appium.txt", __FILE__), verbose: true else caps = Appium.load_appium_txt file: File.expand_path('./', __FILE__), verbose: true end Appium::Driver.new(caps) Appium.promote_appium_methods AppiumWorld World do AppiumWorld.new end 

这样经过cucumber -p android/ios就能运行相应平台的用例了,Cucumber其余参数自行查阅,和Calabash很是类似。

彻底移除Calabash以后,全部Calabash内置的Steps就没有了,须要从新封装。其中Feature、Scenario、Step的概念没有发生变化,和Calabash彻底一致。从新封装Steps须要依赖appium_lib。为了下降封装成本,提供更多可用的Steps,咱们还引入了selenium-cucumber做为辅助使用。

最后testdata.rb是保存测试数据的文件,例如测试帐号的登陆用户名和密码等数据。

最终须要依赖的库大体是这些:

gem 'appium_lib', '~> 9.4.2' gem 'rest-client', '~> 2.0.2' gem 'rspec', '~> 3.5.0' gem 'cucumber', '~> 2.4.0' gem 'rspec-expectations', '~> 3.5.0' gem 'spec', '~> 5.3.4' gem 'selenium-cucumber', '~> 3.1.5' 

这样就完成了组合方案的总体框架。

新方案造成以后,咱们的提测流程就多了一道保障:

因而每一个客户端RD均可以愉快的点击脚本生成测试报告,提交给QA同窗,省去了你们本地跑测试的时间,也帮助QA同窗节约了时间,不会再出现返工或者测试遗漏的状况。

总体稳定性提升

因为底层切换到了Appium,稳定性提升了,一样的机型再也不出现相似Calabash的不兼容问题了(根据ID没法定位到某个元素),QA同窗在Appium的自动化道路上已经作过很多实践,具备相关经验。在Webview方面支持也是比较好的,相比Calabash只是多了切换Webview和Native上下文的步骤,Appium的优点彻底体现出来了。

iOS接入成本下降

针对Android和iOS的接入成本,也下降到了一致。Android依旧是提供apk,iOS提供重签名的ipa包便可,无需源码集成,这就解决了Calabash方案iOS集成成本大的问题。

元素定位手段增多

公共Steps一次封装到处可用,在跨App复用的业务上,测试代码也几乎能够复用,编写测试脚本的成本再次下降。iOS控件缺乏ID很差定位的问题也获得了解决,Appium支持ID、class、name、XPath等元素定位方式,若是前三者都不可用的状况下,使用相对复杂但几乎万能的XPath均可以获得解决。

例如一个复杂的XPath:

Then I press view with xpath "//android.widget.LinearLayout[1] /android.widget.FrameLayout[1]/android.widget.LinearLayout[1] /android.widget.FrameLayout[1]/android.widget.LinearLayout[2] /android.widget.FrameLayout[1]/android.widget.ListView[1] /android.widget.LinearLayout[1]/android.widget.LinearLayout[1]" 

不用担忧这么复杂的XPath应该怎么写,这实际上是最简单的,由于能够经过Appium-inspector抓取获得。固然XPath的写法有不少种,能够选用兼容性更好的写法。

原有脚本无缝迁移

以前在使用Calabash的时候编写的脚本,在封装好公共Steps以后,几乎无缝的进行了迁移,对上层编写测试用例的同窗来讲,几乎没有变化,无需关心是Calabash仍是Appium,使用和原先同样的BDD方式继续愉快的写用例就好。

Calabash方案时期的homepage场景(部分):

切换新方案后homepage场景(部分):

并无太大的差异。

易集成Jenkins,报告可视化

Cucumber能够进行报表的可视化输出,只要在命令后面追加--format html --out reports.html --format pretty,在执行彻底部脚本以后就能够看到生成好的HTML格式的测试报告,也可使用JSON的格式。

集成Jenkins的方式也相对常规,只要安装好须要的依赖就能够。

在测试过程当中,咱们使用了公司内部的云测机器远程平台:

利用远程平台的真机进行远程脚本测试,测试报告示例以下:

在境外业务线客户端进行了自动化测试实践,目前用于固有冒烟自动化,方案先后对好比下。

Calabash方案时期境外点评固有冒烟用例耗时:

新方案境外点评固有冒烟用例耗时(相比以前Calabash方案时期的用例有所增长):

经过数据对比能够看出,用例数量与执行耗时并非严格的线性关系,在用例数量扩大一倍的状况下,耗时并不会线性的扩大一倍。

开发成本:单个用例的开发成本主要根据用例规模相关,开发一个包含7个动做的用例大概耗时30分钟左右,其中包括了定位元素的耗时。多个用例的开发成本不止和用例规模相关,还和用例之间是否有复用的场景相关,这就牵扯到了Scenario拆分粒度的问题,下文中有提到。

目前执行用例美团+点评总耗时20分钟左右,下降了人力成本,避免了QA同窗返工的状况,方案新老交替无缝平滑过渡,维护成本低。这不只是咱们团队对自动化方案的期许,也是自动化测试的价值所在。

问题

scroll or swipe?

在使用UIAutomation的时候,Android页面滑动采起的方式是调用scroll_uiselector方法,例如:

Then /^I scroll to view with text "([^\"]*)"$/ do |value| text = %Q("#{value}") args = scroll_uiselector("new UiSelector().textContains(#{text})") find_element :uiautomator, args end 

可是这种方式存在不稳定性因素,在某些状况下,滑动搜索UI元素很是慢(上下滑动不少次)甚至滑动屡次最后仍然搜索不到,脚本会执行失败。在比较复杂的App上很容易出现,是总体脚本稳定性和成功率的瓶颈。若是更换为UIAutomation2,就可使用swipe语句进行相对精准的滑动:

swipe start_x: start_x, start_y: start_y, end_x: start_x, end_y: start_y - pixel.to_i 

根据撰写本文时Appium的最新版本v1.6.5进行实践,发现切换UIAutomation2后使用swipe滑动,对比scroll的方式成功率提升了一倍多,耗时减半,效果很是显著。虽然其余语句会略微受一点影响,不过总体改动幅度很小,性价比很高,并且UIAutomation2还支持对Toast的识别,总体稳定性大幅提升,建议使用UIAutomation2。

Scenario拆分粒度

在不少状况下,一个test case是由一个或多个Scenario组成的,不一样的test case又会存在部分Scenario复用的状况,明确Scenario的拆分粒度能够帮助开发人员下降测试脚本的编写成本,达到必定程度上的App内部复用甚至跨App复用。尤为在多人协做的环境下,这是一个很是值得探究的问题。

展望

自动触发云测

目前触发的方式是人工触发Jenkins job,最后输出报告。将来要作的是在特定的时期自动触发job进行云端自动化,触发时期可能会参考App的开发周期时间节点。

人人都是测试工程师

咱们但愿团队内人人都具有良好的测试思惟,能站在测试的角度想问题,领悟测试驱动开发的意义。经过简单的方式让团队内的同窗们参与测试,体会测试,写出更优秀的代码。

  1. Appium Doc
  2. appium/ruby_lib docs
  3. selenium-cucumber-ruby Canned Steps

立成,美团点评酒旅境外度假研发组Android高级开发工程师,在Android开发、跨平台开发、移动端测试等领域有必定的实践经验,热爱新技术并愿意付诸实践,致力于产出高质量代码。

酒旅境外度假研发组,负责美团点评境外度假业务。美团点评海外站覆盖全球100多个国家地区,收录美食、购物、酒店、景点等各种海外商户超过500万家,为出国游玩用户提供吃、玩、住、买、交通一站式解决方案。咱们的使命是作「最好用的境外中文消费指南」,全方位解决用户海外旅行中的问题,最终成为出境游行业技术领域智能化、国际化的标杆!咱们团队长期招聘Android、iOS、FE、Java、算法等技术方向的工程师,诚挚欢迎投递简历至hongguangyan#meituan.com。

【思考题】 本文为你们介绍的新型客户端自动化测试方案大大下降了自动化测试的成本,可是依然存在测试脚本的迭代与维护的问题。那么应该在什么时间节点或者时间段对脚本进行维护,才能保证在测试过程当中不会由于脚本滞后而致使测试失败?如何将这部分红本降到最低?如何实现人人都是测试工程师的愿景?

相关文章
相关标签/搜索