共计 5774 个字符,预计需要花费 15 分钟才能阅读完成。
App 自动化测试中有些常见痛点问题,如果框架不能很好的解决,就可能呈现元素定位超时找不到的状况,自动化也就被打断终止了。很容易打消做自动化的激情,导致从入门到放弃。比方上面的两个问题:
一是 App 启动加载工夫较久(可能 App 自身加载慢,可能挪动设施自身加载利用速度慢,也可能首页广告工夫较长)。
另一个是各种弹框的呈现,广告弹框,降级弹框,评估弹框等。在框架中如果不能解决好下面的状况,
以雪球 App 呈现的几种弹框举例:
弹框一:
弹框二:
弹框三:
- 弹框的影响范畴
- 弹框对咱们自动化的影响次要是用例执行的打断,而至于弹框中广告内容的跳转或评估信息填写等属于另外的测试,因而咱们次要是要将弹框解决隐没,使利用回到用例执行的 PO;
- 弹框的隐没形式
- 察看弹框,咱们会发现个别为了保障用户体验,弹框都会不便用户进行一键打消,例如上述中雪球的各种弹框,可能点击一个叉号,可能任意点击其余中央,或者评估框这种间接点击“下次再说”等。
- 弹框的解决成果
- 自动化执行的任何时候,任意的弹框都可能呈现,在这个时候用例不能失败,须要将对应的弹框正确处理后继续执行原用例,原用例的执行过程不受影响。
- 将须要解决的弹框元素退出到一个黑名单 List 中,遍历 List,通过 findElements 办法失去的 List 大小来判断弹框元素是否存在,存在即点击解决
public static void handleAlert(){List<By> alertBox = new ArrayList<>();
alertBox.add(By.id("ib_close")); // 广告弹框
alertBox.add(By.id("md_buttonDefaultNegative")); // 评估弹框
alertBox.forEach(alert->{
By adsLocator = alert;
List<WebElement> ads = driver.findElements(adsLocator);
if (ads.size() >= 1) {ads.get(0).click();}
});
}
-
将 handleAlert()办法加到 driver.findElement 办法之前,使定位前先判断弹框的存在与否并进行解决
public static WebElement findElement(By by) {System.out.println(by); handleAlert(); return driver.findElement(by); }
上述办法初步解决了弹框问题,然而毛病也很显著。
毛病:每次定位元素前都须要解决弹框,影响执行效率,速度较慢 因而咱们引入 try catch 来解决此问题
咱们利用 try catch 的异样捕捉解决的机制,让元素仅在定位失败时才进入弹框解决 handleAlert()办法,处理完毕后从新返回 driver.findElement(by),对原 case 元素持续进行定位执行;这样就大大晋升了解决效率,使解决更为精准。
public static WebElement findElement(By by) {
try {System.out.println(by);
return driver.findElement(by);
} catch (Exception e) {System.out.println("进入弹框解决");
handleAlert();
return driver.findElement(by);
}
}
递归解决:
个别状况下咱们一次只会呈现一个弹框,然而例外的是可能有一个以上的弹框同时呈现,这样的话尽管解决了其中一个弹框,然而剩下的弹框仍然会阻断用例的失常执行,这个时候就能够应用递归的办法,在解决完弹框后返回 findElement 办法本身,持续进行 try catch,使之进入弹框解决逻辑
public static WebElement findElement(By by) {
try {System.out.println(by);
return driver.findElement(by);
} catch (Exception e) {System.out.println("进入弹框解决");
handleAlert();
return findElement(by);
}
}
留神:
应用递归办法后有一个问题,就是如果并不是因为某个弹框的呈现而导致的定位失败,而这个时候通过 try catch 进入到弹框解决逻辑后,因为并未匹配到弹框元素,所以递归就会进入一个死循环,一直反复着弹框解决的逻辑,所以应用递归时咱们也须要对其次数进行限度;个别两个弹框同时呈现曾经算多的了,所以倡议能够将递归的次数限度到最多两次便退出。
static int i = 1;
public static WebElement findElement(By by) {
try {System.out.println(by);
return driver.findElement(by);
} catch (Exception e) {if (i > 2){ // 设置最多递归两次
i = 1;
return driver.findElement(by);
}
System.out.println("进入弹框解决第"+i+"次");
handleAlert();
i++;
return findElement(by); // 最初调用本身实现递归,避免多弹框同时呈现造成定位失败
}
}
依照下面的办法,看似曾经很好的解决了弹框的解决,然而能够留神到的是:
- 在查看弹框的时候仍然应用的是 appium 的定位,在以后页面中依据元素的属性去一一查找定位
- 所有的黑名单中的弹框都会被定位查找一遍
- 而咱们理论中最想要的也是最有效率的办法应该是:
- 只有在以后页面中存在的弹框才对其进行定位、操作、解决。为了达到咱们想要的成果,就须要借助于 PageSource 了。
-
1)appium 的 driver 提供了一个 getPageSource 办法,此办法能够在以后页面能够失去一个文本字符串,也能够了解为以后页面的 xml,咱们利用这种 xml 文原本进行判断,就比用 appium 一一定位的形式要疾速和精准的多了
String pageSource = driver.getPageSource();
2)设置黑名单,黑名单要应用元素的 xpath,用来和 PageSource 文本做匹配,判断此弹框是否存在以后页面
String adBox = "com.xueqiu.android:id/ib_close";
String gesturePromptBox = "com.xueqiu.android:id/snb_tip_text";
String evaluateBox = "com.xueqiu.android:id/md_buttonDefaultNegative";
HashMap<String,By> map = new HashMap<>();
map.put(adBox,By.id("ib_close"));
map.put(gesturePromptBox,By.id("snb_tip_text"));
map.put(evaluateBox,By.id("md_buttonDefaultNegative"));
4)遍历 map,判断黑名单弹框元素是否存在于以后 pageSource,存在即依据弹框解决形式进行点击或其余操作 (如上述中的新性能提醒弹框,点击弹框本身无奈打消,需点击页面其余部分方可打消) 解决
map.entrySet().forEach(entry ->{if (pageSource.contains(entry.getKey())){if (entry.getKey().equals("com.xueqiu.android:id/snb_tip_text")){System.out.println("gesturePromptBox found");
Dimension size = driver.manage().window().getSize();
// 点击屏幕的核心地位,打消新性能提醒弹框
new TouchAction<>(driver).tap(PointOption.point(size.width/2,size.height/2)).perform();}else {
// 其余弹框间接点击打消
driver.findElement(entry.getValue()).click();}
}
});
// 很多弹框的话,最好的是间接定位到到底哪个弹框在界面上,元素的判断应用 xpath
public static void handleAlertByPageSource(){String pageSource = driver.getPageSource();// 能够失去一个文本字符串,也能够了解为以后页面的 xml
// 黑名单
String adBox = "com.xueqiu.android:id/ib_close";
String gesturePromptBox = "com.xueqiu.android:id/snb_tip_text";
String evaluateBox = "com.xueqiu.android:id/md_buttonDefaultNegative";
// 将标记和定位符存入 map
HashMap<String,By> map = new HashMap<>();
map.put(adBox,By.id("ib_close"));
map.put(gesturePromptBox,By.id("snb_tip_text"));
map.put(evaluateBox,By.id("md_buttonDefaultNegative"));
// 长期批改隐式等待时间,避免查找黑名单中元素过久
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
// 遍历 map,判断黑名单弹框元素是否存在于以后 pageSource,存在即点击解决
map.entrySet().forEach(entry ->{if (pageSource.contains(entry.getKey())){if (entry.getKey().equals("com.xueqiu.android:id/snb_tip_text")){System.out.println("gesturePromptBox found");
Dimension size = driver.manage().window().getSize();
new TouchAction<>(driver).tap(PointOption.point(size.width/2,size.height/2)).perform();}else {driver.findElement(entry.getValue()).click();}
}
});
// 判断实现后将隐式等待时间复原
driver.manage().timeouts().implicitlyWait(8,TimeUnit.SECONDS);
}
6)最初将 findElement 办法中的 handleAlert 办法替换为 handleAlertByPageSource 办法即可
static int i = 1;
public static WebElement findElement(By by) {
try {System.out.println(by);
return driver.findElement(by);
} catch (Exception e) {if (i > 2){ // 设置最多递归两次
i = 1;
return driver.findElement(by);
}
System.out.println("进入弹框解决第"+i+"次");
handleAlertByPageSource();
i++;
return findElement(by); // 最初调用本身实现递归,避免多弹框同时呈现造成定位失败
}
}
再来解决首页加载时可能呈现的坑。
App 启动加载工夫较久(可能 App 自身加载慢,也可能是挪动设施自身加载利用速度慢,也可能首页广告工夫较长),导致定位超时,用例失败。对此咱们又如下两步解决办法。
如题目所述,对首页进入应用显示期待,利用搜寻控件的呈现来判断是否进入了首页,这样不影响其余元素隐式期待的工夫,也解决了首页初始化加载工夫过长的问题。
例如雪球仅在进入首页后会呈现 id 为 user_profile_container 的用户信息控件,那么咱们就能够以此为根据来判断利用是否加载实现进入了首页。
在启动办法中退出显示期待上述首页控件 30 秒,到控件可被定位时确认进入首页。
new WebDriverWait(driver,30)
.until(ExpectedConditions.visibilityOfElementLocated(By.id("user_profile_container")));
毛病:
然而这样有个状况不能解决:若加载实现后有弹框呈现,可能就始终无奈定位到首页元素,然而实际上曾经加载实现,比方下图的首页广告弹框。
文章第二局部介绍了利用 PageSource 来判断弹框是否存在的办法,在这里仍然实用,还是相熟的滋味,还是同样的套路,将弹框元素 xpath 也退出 PageSource 判断,这样无论首页控件和首页弹框哪一个被发现,就都能够判断利用曾经加载实现,胜利进入首页,剩下的就能够交给用例和其余解决逻辑了
new WebDriverWait(driver,30)
.until(x ->{String xml = driver.getPageSource();
Boolean checkResult = xml.contains("user_profile_container") || xml.contains("com.xueqiu.android:id/ib_close");
System.out.println("主页元素查找的后果是:" + checkResult);
return checkResult;
});
好了,通过下面的剖析之后,咱们终于搞定了入门 APP 自动化测试时的老大难问题。搞定了弹框及首页启动时加载实现如何判断解决。