关于软件测试:干货-解决-App-自动化测试的常见痛点弹框及首页启动加载完成判断处理

4次阅读

共计 5774 个字符,预计需要花费 15 分钟才能阅读完成。

App 自动化测试中有些常见痛点问题,如果框架不能很好的解决,就可能呈现元素定位超时找不到的状况,自动化也就被打断终止了。很容易打消做自动化的激情,导致从入门到放弃。比方上面的两个问题:

一是 App 启动加载工夫较久(可能 App 自身加载慢,可能挪动设施自身加载利用速度慢,也可能首页广告工夫较长)。

另一个是各种弹框的呈现,广告弹框,降级弹框,评估弹框等。在框架中如果不能解决好下面的状况,

以雪球 App 呈现的几种弹框举例:

弹框一:

弹框二:

弹框三:

  • 弹框的影响范畴
  • 弹框对咱们自动化的影响次要是用例执行的打断,而至于弹框中广告内容的跳转或评估信息填写等属于另外的测试,因而咱们次要是要将弹框解决隐没,使利用回到用例执行的 PO;
  • 弹框的隐没形式
  • 察看弹框,咱们会发现个别为了保障用户体验,弹框都会不便用户进行一键打消,例如上述中雪球的各种弹框,可能点击一个叉号,可能任意点击其余中央,或者评估框这种间接点击“下次再说”等。
  • 弹框的解决成果
  • 自动化执行的任何时候,任意的弹框都可能呈现,在这个时候用例不能失败,须要将对应的弹框正确处理后继续执行原用例,原用例的执行过程不受影响。
  1. 将须要解决的弹框元素退出到一个黑名单 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();}
        });
    }
  1. 将 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 自动化测试时的老大难问题。搞定了弹框及首页启动时加载实现如何判断解决。

正文完
 0