TA的每日心情 | 无聊 2024-7-12 13:16 |
---|
签到天数: 1 天 连续签到: 1 天 [LV.1]测试小兵
|
用Appium 做过IOS自动化的都知道,ios下的自动化是特别慢的,有时候查找一个控件居然能耗时两三分钟,试问这样的速度谁能忍受的了,有些公司为此干脆就做IOS自动化了。难道IOS的自动化就真的是这么慢么?非也,慢是因为appium的某些方法没有实现好,经过优化之后是可以摆脱这个问题的,下面给大家讲解下appium ios的优化策略。
关于appium ios 速度策略优化,网上能够搜索到的好像就是只有一篇,https://testerhome.com/topics/3352,百度很多网站也是转发的这一篇文章。这篇文章说了大概的原因却没有根本的解决问题。
我们知道影响ios的自动化速度慢的原因主要就是2个方面:
1、输入操作 ,这个跟android是一样的情况
2、XPATH查找 特别耗时。
跟页面控件的多少有关,控件多的页面比如首页,就出现查找元素耗费两三分钟的情况。这主要是因为appium的xpath实现方式不好造成的,appium 实现xpath查找是先通过苹果的 UIAutomation框架 instrument JS UIATarget.localTarget().logElementTree();获取到控件树结构,再把它格式化成XML,然后再通过xpath遍历查找到控件,最后又转换为底层的instrument JS去执行操作。这其中的获取跟解析都特别耗时。
针对这两个问题,之前文章提到的方法是,尽量少用xpath定位方式,尽量减少通信,尝试使用通过driver.getPageSource()后自己重新查找方法。输入操作用setvalue代替。但是你会发现ios下的app根本现在根本没有id属性,更可恶的是有大部分的控件name,label等属性都是空的(虽然界面有文字)只能通过又丑又长的xpath表达式定位,例如:
//UIAApplication[1]/UIAWindow[1]/UIATableView[1]/UIATableCell[1]/UIAButton[2]。这种xpath查找效率是很低的。所以虽然xpath可恨但我们还是不可避免。对于重新查找方法更不可取,一是对编程要求高,二是不知道有多少坑。对于减少通信的做法,只能适应于本地模式,如果是这种方式,不如直接用UIAutomation,用啥appium。用appium就是为了解决不同设备端的整合,分布式并发执行问题的,而这免不了通信,所以前面的文章并没有把问题根本解决。
下面给大家讲解下我的解决思路:
通过分析,我发现appium解析耗费大量时间解析xpath最终又是转换为instrument JS,为什么我们不能绕过解析xpath过程,直接把xpath翻译成instrument JS?答案是肯定的,庆幸appium提供了直接执行instrument JS的定位方式ByIosUiautomaiton.
经过优化后,ios自动化的执行速度得到了大幅提升,原来操作一个控件需要两三分钟的,也只需要2秒左右了!
具体代码实现如下:(有兴趣的可以自己去查看下instrument JS语法)
1、xpath定位替换代码
- /**
- * //UIAApplication[1]/UIAWindow[1]/UIATableView[1]/UIATableCell[1]/UIAButton[3]
- * @param str
- * @return
- */
- private String xpathToIosLocatorJs(String str){
- String[] array=str.trim().replace("//","/").split("/");
- for (int i=1;i<array.length;i++){
- String tag=array[i];
- String[] tagArray=tag.split("\\[");
- String tagName=tagArray[0];
- if (tagArray.length==2){
- if (!tagName.contains("UIAApplication")&&!tagName.contains("UIAWindow")){
- String indexStr=tagArray[1].replace("]","");
- if (checkStringIsInt(indexStr)){
- int index=Integer.valueOf(indexStr)-1;
- indexStr=String.valueOf(index);
- tag=tag.replace("["+tagArray[1],"["+indexStr+"]");
- }else {
- indexStr="\""+indexStr.split("=")[1].replace("\"","").replace("'","")+"\"";
- tag=tag.replace("["+tagArray[1],"["+indexStr+"]");
- }
- }
- }
- switch (tagName){
- case "UIAApplication":
- tagName="frontMostApp";
- break;
- case "UIAWindow":
- tagName="mainWindow";
- break;
- case "UIATableCell":
- tagName="cells";
- break;
- case "*":
- tagName="frontMostApp().mainWindow().elements";
- break;
- default:
- tagName=tagName.replace("UIA","")+"s";
- break;
- }
- tagName=tagName+"()";
- StringBuffer sb=new StringBuffer();
- if (!tagName.equals("")){
- sb.append(tagName.charAt(0));
- tagName=tagName.replace(tagName.charAt(0),sb.toString().toLowerCase().charAt(0));
- }
- tag=tag.replace(tagArray[0],tagName);
- if (tagName.contains("frontMostApp")||tagName.contains("mainWindow")){
- tag=tag.replace("["+tagArray[1],"");
- }
- str=str.replace(array[i],tag);
- }
- str=" var webElement="+str.replace("//","UIATarget.localTarget().").replace("/",".")+";";
- return str;
- }
- private String xpathToUiautomatorJs(String str){
- str=xpathToIosLocatorJs(str);
- str=str.replace("//","target.").replace("/",".").replace("var webElement=","");
- String[] array=str.split("\\.");
- for (int i=0;i<array.length;i++){
- String tagName=array[i];
- if (tagName.contains("UIATarget")||tagName.contains("localTarget")||tagName.contains("frontMostApp")||tagName.contains("mainWindow")){
- str=str.replace(array[i],"");
- }else {
- break;
- }
- }
- str=str.substring(3,str.length()).replace(";","");
- return str;
- }
- //获取元素
- public WebElement getWebelement(Locator locator,WebDriver driver)
- {
- WebElement webElement;
- switch (locator.getLocatorType())
- {
- case "xpath" :
- if (driver instanceof IOSDriver){
- IOSDriver iosDriver=(IOSDriver) driver;
- String uiautomatorJs=xpathToUiautomatorJs(locator.getLocatorValue());
- log.info("将xpath转换成uiautomatorJs"+uiautomatorJs);
- webElement=iosDriver.findElementByIosUIAutomation(uiautomatorJs);
- }else if (driver instanceof AndroidDriver){
- String locatorValue=locator.getLocatorValue();
- if (locatorValue.contains("//*[@text")){
- String text=locatorValue.split("=")[1].replace("'","").replace("]","").replace("\"","");
- String uiautomatorExpress="new UiSelector().text(\""+text+"\")";
- webElement=((AndroidDriver) driver).findElementByAndroidUIAutomator(uiautomatorExpress);
- }else if (locatorValue.contains("//*[contains(@text")){
- String text=locatorValue.split(",")[1].replace("'","").replace("]","").replace("\"","").replace(")","");
- String uiautomatorExpress="new UiSelector().textContains(\""+text+"\")";
- webElement=((AndroidDriver) driver).findElementByAndroidUIAutomator(uiautomatorExpress);
- }else {
- webElement=driver.findElement(By.xpath(locator.getLocatorValue()));
- }
- }else {
- webElement=driver.findElement(By.xpath(locator.getLocatorValue()));
- }
- break;
- case "id":
- webElement=driver.findElement(By.id(locator.getLocatorValue()));
- break;
- case "cssSelector":
- webElement=driver.findElement(By.cssSelector(locator.getLocatorValue()));
- break;
- case "name":
- webElement=driver.findElement(By.name(locator.getLocatorValue()));
- break;
- case "className":
- webElement=driver.findElement(By.className(locator.getLocatorValue()));
- break;
- case "linkText":
- webElement=driver.findElement(By.linkText(locator.getLocatorValue()));
- break;
- case "partialLinkText":
- webElement=driver.findElement(By.partialLinkText(locator.getLocatorValue()));
- break;
- case "tagName":
- webElement=driver.findElement(By.tagName(locator.getLocatorValue()));
- break;
- case "iosUIAutomation":
- if (driver instanceof IOSDriver){
- webElement=((IOSDriver) driver).findElementByIosUIAutomation(locator.getLocatorValue());
- }else {
- webElement=driver.findElement(By.xpath(locator.getLocatorValue()));
- }
- break;
- default :
- webElement=driver.findElement(By.xpath(locator.getLocatorValue()));
- break;
- }
- return webElement;
- }
复制代码
2、input输入替代方法代码
- /**
- * 文本框输入操作
- * @param locator 元素locator
- * @param value 输入值
- */
- public void type(Locator locator,String value,WebDriver driver)
- {
- try {
- WebElement webElement=findElement(locator,driver);
- if (driver instanceof AppiumDriver){
- if (driver instanceof AndroidDriver){
- AppiumDriver androidDriver=(AppiumDriver) driver;
- if (androidDriver.getContext().contains("NATIVE_APP")){
- MobileElement mobileElement= (MobileElement)webElement;
- mobileElement.setValue(value);
- }else {
- webElement.sendKeys(value);
- }
- }else {
- MobileElement mobileElement= (MobileElement)webElement;
- mobileElement.setValue(value);
- }
- }else {
- webElement.sendKeys(value);
- }
- log.info("input输入:"+locator.getLocatorName()+"["+"By."+locator.getLocatorType()+":"+locator.getLocatorValue()+"value:"+value+"]");
- } catch (Exception e) {
- log.error("找不到元素,input输入失败:"+locator.getLocatorName()+"["+"By."+locator.getLocatorType()+":"+locator.getLocatorValue()+"]");
- e.addSuppressed(new Exception(""));
- e.addSuppressed(new Exception("找不到元素,input输入失败:"+getLocatorInfo(locator)));
- e.printStackTrace();
- throw e;
- }
- }
复制代码 原创文章,转载请注明出处
|
|