2020-04-08

iOS Appium自动化测试框架原理简析 

原文链接:https://easeapi.com/blog/blog/103-appium.html

Appium是目前比较好用的跨平台自动化测试框架,在iOS端采用WebDriverAgent作为webdriver驱动,实现了自动化脚本编写到运行的全流程覆盖。

在Xcode 8之前,基于UI Automation的自动化测试方案是比较好用且非常流行的。但在Xcode 8之后,苹果在instruments工具集中直接废除了Automation组件,转而支持使用UI Testing。

UI Testing

从Xcode 7开始,苹果提供了UI Testing框架,也就是我们在APP test工程中使用的XCTest的那一套东西。UI Testing包含几个重要的类,分别是XCUIApplication、XCUIElement、XCUIElementQuery。

XCUIApplication

代表正在测试的应用程序的实例,可以对APP进行启动、终止、传入参数等操作。

- (void)launch;- (void)activate;- (void)terminate;@property(nonatomic,copy)NSArray *launchArguments;@property(nonatomic,copy)NSDictionary *launchEnvironment;

XCUIApplication在iOS上提供了两个初始化接口:

//Returns a proxy for the application specified by the "Target Application" target setting.- (instancetype)initNS_DESIGNATED_INITIALIZER;//Returns a proxy for an application associated with the specified bundle identifier.- (instancetype)initWithBundleIdentifier:(NSString*)bundleIdentifierNS_DESIGNATED_INITIALIZER;

其中initWithBundleIdentifier接口允许传入一个bundle id来操作指定APP。这个技术点是iOS APP能够自动化测试的关键所在。

XCUIElement

表示界面上显示的UI元素。

XCUIElementQuery

用于定位UI元素的查询对象。

上述几个模块就是一个UI测试框架的核心能力,后面在写Appium的自动化脚本时也是一样的套路:启动APP->定位UI元素->触发操作。

WebDriverAgent

WebDriverAgent是Facebook开发的基于XCTest.framework的开源项目,实现了在iOS上支持WebDriver协议的服务,可以用来启动/终止APP,点击/滑动页面。

webdriver协议是一套基于HTTP协议的JSON格式规范,协议规定了不同操作对应的格式。之所以需要这层协议,是因为iOS、Android、浏览器等都有自己的UI交互方式,通过这层”驱动层“屏蔽各平台的差异,就可以通过相同的方式进行自动化的UI操作,做网络爬虫常用的selenium是浏览器上实现webdriver的驱动,而WebDriverAgent则是iOS上实现webdriver的驱动。

使用Xcode打开WebDriverAgent项目,连接上iPhone设备之后,选中WebDriverAgentRunner->Product->Test,则会在iPhone上安装一个名为WebDriverAgentRunner的APP,这个APP实际上是一个后台应用,直接点击ICON打开的话会退出。

具体到代码层面,WebDriverAgentRunner的入口在UITestingUITests.m文件

- (void)testRunner{  FBWebServer *webServer = [[FBWebServer alloc] init];  webServer.delegate= self;  [webServer startServing];}

会在手机上6100端口启动一个HTTP server,startServing方法内部就是一个死循环,监听网络传输过来的webdriver协议的数据,解析并处理点击事件。

有意思的是,WebDriverAgent并没有使用XCUIApplication的initWithBundleIdentifier方法,而是使用了initPrivateWithPath的私有方法。测试发现两者效果上没什么区别,这里暂时不清楚为什么不直接使用initWithBundleIdentifier。

WebDriverAgent如何处理点击事件的?

从WebDriverAgent的源码可以清晰的看到,在Commands目录,是支持的操作类集合。每一个操作都通过routes类方法注册对应的路由和处理该路由的函数。手势处理在FBTouchActionCommands.m中,

+ (NSArray*)routes{return@[    [[FBRoute POST:@"/wda/touch/perform"] respondWithTarget:selfaction:@selector(handlePerformAppiumTouchActions:)],    [[FBRoute POST:@"/wda/touch/multi/perform"] respondWithTarget:selfaction:@selector(handlePerformAppiumTouchActions:)],    [[FBRoute POST:@"/actions"] respondWithTarget:selfaction:@selector(handlePerformW3CTouchActions:)],  ];}

可以看到/wda/touch/perform、/wda/touch/multi/perform、/actions路由负责处理不同的点击事件。那么当一个点击的url请求过来时,如何转化为iOS的UIEvent事件呢?跟踪代码发现核心代码是:

[[XCUIDevice.sharedDevice eventSynthesizer]synthesizeEvent:record completion:(id)^(BOOL result, NSError *invokeError) {handlerBlock(record, invokeError);}];

XCUIDevice的eventSynthesizer是私有方法,通过synthesizeEvent发送XCSynthesizedEventRecord(也是私有类)事件。到这里WebDriverAgent的流程就很清除了。实际上由于使用了很多私有方法,WebDriverAgent并非仅能自动化当前APP,也是可以操作手机屏幕以及任意APP的。

Appium

上面介绍的UI Testing和WebDriverAgent都是iOS上的内容。实际上,在更多的时候我们需要考虑跨平台,从笔者调研来看,现阶段比较好的方案是Appium。Appium是一个开源测试自动化框架,可用于iOS、Android和web应用程序测试,支持python、JAVA、php等多种语言编写测试用例。Appium包含客户端和服务端等模块。

Appium客户端

在iOS上的客户端实际上就是使用了WebDriverAgent,作为实现webdriver协议的驱动层。

Appium服务端

Appium的服务端是一个桌面应用,用于和客户端通信,启动Appium的服务端之后,会在电脑上启动一个默认端口号是4723的HTTP服务。当我们编写完脚本执行时,脚本代码会被转换为webdriver协议的JSON数据,通过HTTP请求发送到电脑的4723端口。Appium服务端将脚本的执行请求下发给客户端(请求客户端的6100端口),客户端同样使用webdriver协议响应。

Appium的部署

安装各种驱动

brew install libimobiledevicenpminstall -g ios-deploy#appium-doctor可检查依赖是否安装成功  npminstall -g appium-doctor#检查依赖项  appium-doctor -ios

安装appium-desktop

下载安装之后,需要对WebDriverAgent修改下证书信息,使其可以真机调试。

cd/Applications/Appium.app/Contents/Resources/app/node_modules/appium/node_modules/appium-youiengine-driver/node_modules/appium-webdriveragent  ./Scripts/bootstrap.sh-d

连接真机后,打开WebDriverAgent.xcodeproj,Product->Test运行WebDriverAgentRunner(需要配置证书)。终端会显示一个地址 http://169.254.138.98:8100 访问 http://169.254.138.98:8100/status打开有json信息则表示服务连接成功。

需要注意的是,Facebook原始的WebDriverAgent功能上似乎有些问题,appium-desktop自带的WebDriverAgent版本据说是经过优化修改过的,运行正常。

部署完成之后打开Appium,Start Server后即可编写脚本了。一个典型的monkey脚本如下:

#!/usr/bin/python# coding=utf-8importunittestimportosfromappiumimportwebdriverfromtimeimportsleepfromappium.webdriver.common.touch_actionimportTouchActionimportrandomclassAppTest(unittest.TestCase):defsetUp(self):print("setUp")        udid ="c9d719e41f6a9ae00353db126a6561fdf032cc23"bundleId ="com.easeapi"ifFalse:#new appapp = os.path.abspath('/Users/easeapi.app')            self.driver = webdriver.Remote(command_executor ='http://127.0.0.1:4723/wd/hub', desired_capabilities = {'app':app,'platformName':'iOS','platformVersion':'12.4.3','deviceName':'EaseapiPhone','bundleId': bundleId,'udid': udid})else:#exist appself.driver = webdriver.Remote(command_executor ='http://127.0.0.1:4723/wd/hub', desired_capabilities = {'platformName':'iOS','platformVersion':'12.4.3','deviceName':'EaseapiPhone','bundleId': bundleId,'udid': udid})deftearDown(self):#self.driver.quit()deftest_monkey(self):__size = self.driver.find_element_by_xpath('//UIAApplication[1]').size        window_width = __size['width']        window_height = __size['height']whileTrue:            sleep(1.0)            _x = random.uniform(0, window_width)            _y = random.uniform(0, window_height)            print('x:%f y:%f') % (_x, _y)            TouchAction(self.driver).tap(x=_x, y=_y).perform()if__name__ =='__main__':    suite = unittest.TestLoader().loadTestsFromTestCase(AppTest)    unittest.TextTestRunner(verbosity=2).run(suite)

执行该脚本,即可对bundle id为com.easeapi的app进行monkey测试。如果想自定义事件也比较简单:

button= self.driver.find_element_by_accessibility_id("按钮")button.click()

很多时候,编写脚本是一件很繁琐无趣的工作,好在Appium提供了录制的功能。我们上面仅仅启动了Appium的服务。实际上通过Appium也是可以直接在电脑上操作手机的。打开Appium,点击搜索按钮,在JSON Representation区域填写如下模板内容:

{  "platformName":"ios",  "platformVersion":"12.4.3",  "udid":"c9d719e41f6a9ae00353db126a6561fdf032cc23",  "deviceName":"EaseapiPhone",  "automationName":"XCUITest",  "bundleId":"com.easeapi",  "xcodeSigningId":"iPhone Developer"}

完成后点击Start Session,即可在电脑上直接操作iPhone手机,使用录制功能可以将每一步的点击操作转化为脚本文件,大大较少了开发工作量。

最后

以上就是Appium的实现原理和简单使用介绍,总体来看Appium是一个比较优秀的自动化测试方案,值得推广使用。最后简单说下其他方案的调研结果:

fastmonkey:在Xcode11上已无法运行。

swiftmonkey:使用Swift3.4开发,最新Xcode已经不支持这个版本的Swift。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • 曾看到网上有一篇文章,题目是“这个春节不过了,请退我一岁。” 2020,以它特有的方式与我们相遇。 在这个特殊的时...
    红英读书阅读 66评论 0 0
  • 叠翠藏庙宇 林深寻芳踪 野趣最难得 无畏才是真
    辉煌Ad098阅读 146评论 2 16
  • 老陈躺在了圆餐桌旁的冰凉地面上,闭着双眼,嘴角还有一点残余的白沫,老宋跪坐在他一旁,左手轻拍着他的脸,“老...
    简宁直树阅读 153评论 0 1
  • 中国科幻第一人刘慈欣有一种写作手法,叫做“大历史写作法”。什么意思呢?就是站在一个极远极远的未来,像写史书一样记录...
    牙医孙杰阅读 200评论 0 2
  • 天气:晴 星期三 2020.4.1 三月过,四月来。 在四月开头的一天,我完成了一件手工作品,...
    蓝莓酱呀阅读 1,212评论 15 11