Appium的代码实例及日志分析
本文内容:
Android及IOS基于TestNG的代码结构示例,
常用的元素定位方式的介绍
部分项目中使用的功能代码示例
Appium日志的具体分析
部分需要理解的概念
Android示例代码(TestNG):
publicclassAndroidTest{protectedAndroidDriver<MobileElement>driver;URLurl=newURL("http://127.0.0.1:4723/wd/hub");@BeforeSuitepublicvoidsetUp()throwsException{DesiredCapabilitiescapabilities=newDesiredCapabilities();capabilities.setCapability(MobileCapabilityType.DEVICE_NAME,"AndroidPhone");capabilities.setCapability(AndroidMobileCapabilityType.APP_PACKAGE,"com.example.dev");capabilities.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY,".MainActivity");capabilities.setCapability(MobileCapabilityType.NO_RESET,true);......driver=newAndroidDriver<>(url,capabilities);}@AfterSuitepublicvoidtearDown()throwsException{if(driver!=null){driver.quit();}}@Testpublicvoidtest_001(){}//TestCaseOne@Testpublicvoidtest_002(){}//TestCaseTwo}
IOS示例代码(TestNG):
publicabstractclassIOSTest{protectedIOSDriver<MobileElement>driver;URLurl=newURL("http://127.0.0.1:4723/wd/hub");@BeforeSuitepublicvoidsetUp()throwsException{DesiredCapabilitiescapabilities=newDesiredCapabilities();capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME,"iOS");capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION,"10.3");capabilities.setCapability(MobileCapabilityType.DEVICE_NAME,"MyiPhone6");capabilities.setCapability(MobileCapabilityType.UDID,"c4ef2cbc8a1b39123838a8ad9fdea45547e44c20");capabilities.setCapability(IOSMobileCapabilityType.BUNDLE_ID,"com.example.dev");......driver=newIOSDriver<>(url,capabilities);}}
常用的元素定位方式:
Android:
android:id/button1
button1By.classnameView的类型名android.widget.TextView
android.widget.ButtonBy.xpath根据element的属性及DOM层级查找,比较不稳定By.xpath(".//*[@text='Title']")根据text属性查找,
一般对于索引不确定的元素采用MobileBy.
AndroidUIAutomator
Android自带UIAutomator框架的定位方式
IOS:
AccessibilityId组件的AccessibilityId,最好用一般同组件的name属性,使用Inspector获得By.classname组件的类型名XCUIElementTypeStaticText
XCUIElementTypeButtonBy.xpath根据element的属性及DOM层级查找,比较不稳定。
By.xpath(".//*[@name='Title']")根据name属性查找,一般都可以用AccessibilityId替代,因为name和AccessibilityId一般是一样的
更精准可以带上classname:
//XCUIElementTypeStaticText[@name="Hello"]
一般对于索引不确定又没有AccessibilityId的元素采用MobileBy.
IosUIAutomation
IOS自带框架UIAutomation的定位方式
AccessibilityId
appium移除了在Selenium上常用的name和tagname定位方式
IOS上表示Accessibility Identifier,通常和Name、Label属性相同
Android上表示content description
交互操作
MobileElement:交互的对象,对应于Android中的一个View对象
点击:element.click();
输入:element.sendKeys("text");
滑动:driver.swipe()
点击:driver.tap();
等待方式:
//隐式等待
//全局设定查找元素时的等待时间,找不到会尝试10秒内间隔查找,找到了继续
//这里设定的值对driver的整个生命周期起作用,从现在开始到下次修改,每次查找都是10秒。
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
//显式等待
//仅仅这次,指明最多等待5秒,指明结束条件为找到元素id=bt_next。超时抛出TimeoutException。
WebElement e = new WebDriverWait(driver, 5).until(
ExpectedConditions.presenceOfElementLocated(By.id("bt_next")));
//强行等待
//线程直接暂停,适合于单纯的等待。不查找元素
Thread.sleep(3000)
DesiredCapabilities
这是一个key-value的集合,用于告诉服务器建立连接的设备信息,不同平台有所不同。appium支持许多的属性设置,可以到官网做个全面的了解。
MobileCapabilityType:不同平台共用
AndroidMobileCapabilityType:Android专用
IOSMobileCapabilityType:IOS专用
Android一般至少需要:
1、platformName
2、platformVersion
3、deviceName
4、appPackage
5、appActivity
IOS一般至少需要:
1、platformName
2、platformVersion
3、deviceName
4、udid
5、bundleId
部分代码示例
//对于弹出的权限对话框,如果找到Allow按钮则一直点击Allow。protectedvoidgrantPermissionIfPrompt(){intcount=0;//atmostfivetimesgrantMobileElementallowBtn=findElement(By.id(ConstConfig.ALLOW_BUTTON));while(allowBtn!=null&&count++<5){//atmost5timetotryallowBtn.click();allowBtn=findElement(By.id(ConstConfig.ALLOW_BUTTON));}}
//向上滑动列表,直到找到目标元素staticpublicMobileElementscrollDownUnitFound(AndroidDriver<MobileElement>driver,Stringcontent)throwsException{intwidth=driver.manage().window().getSize().getWidth();intheight=driver.manage().window().getSize().getHeight();intcount=0;StringxpathStr=createXpathDesc(content);do{if(driver.findElementsByXPath(xpathStr).size()>0){//incaseoftheelementisstillhiding,ortheelementisshowingonlyalittlepartofit.driver.swipe(width/2,height/2,width/2,height/3,600);Thread.sleep(1000);//sleep1secondtoavoidgettingtheelementinthewrongposition.returndriver.findElementsByXPath(xpathStr).get(0);}driver.swipe(width/2,height/2,width/2,height/4,600);count++;}while(count<20);returnnull;}
//生成xpath字符串staticpublicStringcreateXpathDesc(Stringcontent){return".//*[@text='"+content+"']";}
//滑动找到元素,并点击其左侧的CheckBox。CheckBox没有id,也不适合用classname,因为不知道是第几个,只能借助相邻元素坐标偏移。MobileElementel=AndroidHelper.scrollDownUnitFound(driver,voteTarget);if(el!=null){//findthecheckboxtotheleftofthefoundedtarget.inttargetX=el.getLocation().getX()-20;inttargetY=el.getLocation().getY()+1;//event+0isworkingSystem.out.println("coordinates:x="+targetX+"y="+targetY);driver.tap(1,targetX,targetY,300);}
日志分析(Appium on AWS Device Farm):
Appium是Client/Server结构的,所以每一次操作都是以Client向Server发送http请求开始,以Server向Client发送http响应结束。查阅日志可以按这个规律过滤不必要的信息。
Android日志分析:
driver.findElement(By.id("compose_button")).click();
(Adnroid)findElement操作日志:
2017-09-1904:06:27:278-[HTTP]-->POST/wd/hub/session/acfa31ae-321f-4ee1-a34b-294667393f8f/element{"using":"id","value":"compose_button"}2017-09-1904:06:27:278-[debug][MJSONWP]CallingAppiumDriver.findElement()withargs:["id","compose_button","acfa31ae-321f-4ee1-a34b-294667393f8f"]2017-09-1904:06:27:279-[debug][BaseDriver]Validlocatorstrategiesforthisrequest:xpath,id,classname,accessibilityid,-androiduiautomator2017-09-1904:06:27:279-[debug][BaseDriver]Validlocatorstrategiesforthisrequest:xpath,id,classname,accessibilityid,-androiduiautomator2017-09-1904:06:27:279-[debug][BaseDriver]Waitingupto3000msforcondition2017-09-1904:06:27:280-[debug][AndroidBootstrap]Sendingcommandtoandroid:{"cmd":"action","action":"find","params":{"strategy":"id","selector":"compose_button","context":"","multiple":false}}2017-09-1904:06:27:310-[AndroidBootstrap][BOOTSTRAPLOG][debug]Gotdatafromclient:{"cmd":"action","action":"find","params":{"strategy":"id","selector":"compose_button","context":"","multiple":false}}2017-09-1904:06:27:310-[AndroidBootstrap][BOOTSTRAPLOG][debug]GotcommandoftypeACTION2017-09-1904:06:27:310-[AndroidBootstrap][BOOTSTRAPLOG][debug]Gotcommandaction:find2017-09-1904:06:27:311-[AndroidBootstrap][BOOTSTRAPLOG][debug]Finding'compose_button'using'ID'withthecontextId:''multiple:false2017-09-1904:06:27:311-[AndroidBootstrap][BOOTSTRAPLOG][debug]Using:UiSelector[INSTANCE=0,RESOURCE_ID=com.example.hello:id/compose_button]2017-09-1904:06:27:329-[AndroidBootstrap][BOOTSTRAPLOG][debug]Returningresult:{"status":0,"value":{"ELEMENT":"9"}}2017-09-1904:06:27:330-[debug][AndroidBootstrap]Receivedcommandresultfrombootstrap2017-09-1904:06:27:330-[debug][MJSONWP]Respondingtoclientwithdriver.findElement()result:{"ELEMENT":"9"}2017-09-1904:06:27:344-[HTTP]<--POST/wd/hub/session/acfa31ae-321f-4ee1-a34b-294667393f8f/element20053ms-87
(Android)click操作日志:
2017-09-1904:06:27:348-[HTTP]-->POST/wd/hub/session/acfa31ae-321f-4ee1-a34b-294667393f8f/element/9/click{"id":"9"}2017-09-1904:06:27:348-[debug][MJSONWP]CallingAppiumDriver.click()withargs:["9","acfa31ae-321f-4ee1-a34b-294667393f8f"]2017-09-1904:06:27:359-[debug][AndroidBootstrap]Sendingcommandtoandroid:{"cmd":"action","action":"element:click","params":{"elementId":"9"}}2017-09-1904:06:27:375-[AndroidBootstrap][BOOTSTRAPLOG][debug]Gotdatafromclient:{"cmd":"action","action":"element:click","params":{"elementId":"9"}}2017-09-1904:06:27:391-[AndroidBootstrap][BOOTSTRAPLOG][debug]GotcommandoftypeACTION2017-09-1904:06:27:391-[AndroidBootstrap][BOOTSTRAPLOG][debug]Gotcommandaction:click2017-09-1904:06:27:876-[debug][AndroidBootstrap]Receivedcommandresultfrombootstrap2017-09-1904:06:27:876-[debug][MJSONWP]Respondingtoclientwithdriver.click()result:true2017-09-1904:06:27:880-[HTTP]<--POST/wd/hub/session/acfa31ae-321f-4ee1-a34b-294667393f8f/element/9/click200529ms-76
IOS日志分析:
driver.findByAccessibilityId("Compose").click();
(IOS)findElement操作日志:
2017-09-1907:19:36:259-[HTTP]-->POST/wd/hub/session/bbb16560-a4c7-43fc-a5d0-dea9057dff93/element{"using":"accessibilityid","value":"Compose"}2017-09-1907:19:36:259-[debug][MJSONWP]CallingAppiumDriver.findElement()withargs:["accessibilityid","Compose","bbb16560-a4c7-43fc-a5d0-dea9057dff93"]2017-09-1907:19:36:260-[debug][XCUITest]Executingcommand'findElement'2017-09-1907:19:36:260-[debug][BaseDriver]Validlocatorstrategiesforthisrequest:xpath,id,name,classname,-iospredicatestring,-iosclasschain,accessibilityid2017-09-1907:19:36:260-[debug][BaseDriver]Waitingupto3000msforcondition2017-09-1907:19:36:261-[debug][JSONWPProxy]Proxying[POST/element]to[POSThttp://127.0.0.1:8100/session/3FAA9ECD-8EE9-49BC-B1F9-010B03B9821B/element]withbody:{"using":"accessibilityid","value":"Compose"}2017-09-1907:19:37:826-[debug][JSONWPProxy]Gotresponsewithstatus200:{"value":{"ELEMENT":"E56F3927-08E6-4ECD-B3E4-05F30198FA6A","type":"XCUIElementTypeButton","label":"Compose"},"sessionId":"3FAA9ECD-8EE9-49BC-B1F9-010B03B9821B","status":0}2017-09-1907:19:37:829-[debug][MJSONWP]Respondingtoclientwithdriver.findElement()result:{"ELEMENT":"E56F3927-08E6-4ECD-B3E4-05F30198FA6A","type":"XCUIElementTypeButton","label":"Compose"}2017-09-1907:19:37:843-[HTTP]<--POST/wd/hub/session/bbb16560-a4c7-43fc-a5d0-dea9057dff93/element2001570ms-171
(IOS)click操作日志:
2017-09-1907:19:37:869-[HTTP]-->POST/wd/hub/session/bbb16560-a4c7-43fc-a5d0-dea9057dff93/element/E56F3927-08E6-4ECD-B3E4-05F30198FA6A/click{"id":"E56F3927-08E6-4ECD-B3E4-05F30198FA6A"}2017-09-1907:19:37:870-[MJSONWP]Driverproxyactive,passingrequestonviaHTTPproxy2017-09-1907:19:37:870-[debug][XCUITest]Executingcommand'proxyReqRes'2017-09-1907:19:37:870-[debug][JSONWPProxy]Proxying[POST/wd/hub/session/bbb16560-a4c7-43fc-a5d0-dea9057dff93/element/E56F3927-08E6-4ECD-B3E4-05F30198FA6A/click]to[POSThttp://127.0.0.1:8100/session/3FAA9ECD-8EE9-49BC-B1F9-010B03B9821B/element/E56F3927-08E6-4ECD-B3E4-05F30198FA6A/click]withbody:{"id":"E56F3927-08E6-4ECD-B3E4-05F30198FA6A"}2017-09-1907:19:39:829-[debug][JSONWPProxy]Gotresponsewithstatus200:{"status":0,"id":"E56F3927-08E6-4ECD-B3E4-05F30198FA6A","value":"","sessionId":"3FAA9ECD-8EE9-49BC-B1F9-010B03B9821B"}2017-09-1907:19:39:829-[JSONWPProxy]ReplacingsessionId3FAA9ECD-8EE9-49BC-B1F9-010B03B9821Bwithbbb16560-a4c7-43fc-a5d0-dea9057dff932017-09-1907:19:39:834-[HTTP]<--POST/wd/hub/session/bbb16560-a4c7-43fc-a5d0-dea9057dff93/element/E56F3927-08E6-4ECD-B3E4-05F30198FA6A/click2001960ms-118
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。