导航

Appium三种等待

Posted on 2017-07-31 21:19  Young哥哥  阅读(507)  评论(0)    收藏  举报

判断Activity中控件是否出现,可以通过判断页面加载完成后应该出现的元素是否及时出现,

而这个问题又可以转化为如何等待页面元素的出现。今天我们就先从等待方法说起,

首先,看一下我们要测试的APP,本文采用的APP是Android Hybrid,如果想看源码,可以从这里下载:https://github.com/tobecrazy/webview

这个App主要是由一个ImageButton和WebView,而点击显示大约5s之后才会出现红色的ImageButton,点击HOME会返回主页大约5s ImageButton消失。主要是想通过该APP验证以下2点:

a. Native的元素不需要设置等待,Appium会等待元素出现除非超时

b. Pure Web或WebView的元素需要设置等待和selenium一样。

 

APK下载:

 https://github.com/tobecrazy/webview/blob/master/app/build/outputs/apk/app-debug.apk 

 

第一种,死等

Thread.sleep(毫秒)

阻塞线程,必须等到sleep结束之后才会执行后面的脚本。不推荐使用,比如比如设置等待时间30s,无论该元素是否出现,都会暂停case 30s

 

第二种,隐式等待

driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

隐式等待是针对全局所有元素设置的,一个30s超时时间。先去找元素,如果没有出现就等待,直到超过这个时间,就会抛出异常。

 

第三种,显式等待

WebDriverWait wait = new WebDriverWait(driver, 30);

WebElement input = wait.until(new ExpectedCondition<WebElement>() {

@Override

public WebElement apply(WebDriver driver) {

return driver.findElement(By.xpath("//input[@id='index-kw']"));

}

});

  

显式等待,明确告诉driver等待元素出现,如果没有出现就等待30s,如果在30s内已经出现就返回该元素。

 

核心代码

package main.java.com.dbyl.appiumCore.tests;

 

import java.io.File;

import java.io.IOException;

import java.net.URL;

import java.util.Set;

import java.util.concurrent.TimeUnit;

 

import org.openqa.selenium.By;

import org.openqa.selenium.JavascriptExecutor;

import org.openqa.selenium.NoSuchElementException;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.WebElement;

import org.openqa.selenium.remote.CapabilityType;

import org.openqa.selenium.remote.DesiredCapabilities;

import org.openqa.selenium.support.ui.ExpectedCondition;

import org.openqa.selenium.support.ui.WebDriverWait;

import org.testng.Assert;

import org.testng.annotations.AfterMethod;

import org.testng.annotations.BeforeClass;

import org.testng.annotations.BeforeMethod;

import org.testng.annotations.Test;

 

import io.appium.java_client.MobileElement;

import io.appium.java_client.android.AndroidDriver;

import io.appium.java_client.remote.AndroidMobileCapabilityType;

import io.appium.java_client.remote.AutomationName;

import io.appium.java_client.remote.MobileCapabilityType;

import main.java.com.dbyl.appiumServer.AppLogger;

import main.java.com.dbyl.appiumServer.AppiumServerUtils;

 

public class AppWebView {

AndroidDriver<MobileElement> driver;

String keyword = "appium";

URL url;

AppLogger logger = new AppLogger(AppWebView.class);

 

@BeforeClass

public void startAppiumServer() throws IOException, InterruptedException {

url = AppiumServerUtils.getInstance().startServer("127.0.0.1", 4723);

logger.debug("start Appium Server");

}

 

@BeforeMethod(alwaysRun = true)

public void setUp() throws Exception {

// set up appium

DesiredCapabilities capabilities = new DesiredCapabilities();

capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.APPIUM);

capabilities.setCapability(CapabilityType.BROWSER_NAME, "");

capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");

capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");

capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "4.4");

// if no need install don't add this

File classpathRoot = new File(System.getProperty("user.dir"));

File appDir = new File(classpathRoot, "apps");

File app = new File(appDir, "webview.apk");

capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());

 

capabilities.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "com.testerhome.webview");

// support Chinese

capabilities.setCapability("unicodeKeyboard", "True");

capabilities.setCapability("resetKeyboard", "True");

// no need sign

capabilities.setCapability("noSign", "True");

capabilities.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, ".MainActivity");

logger.info("connet to Appium server  " + url.toString());

driver = new AndroidDriver<MobileElement>(url, capabilities);

 

}

 

@Test(groups = { "webView" })

public void webViewTest() throws InterruptedException {

MobileElement clickToPresent = driver.findElementById("com.testerhome.webview:id/action_present");

clickToPresent.click();

MobileElement imageButton = driver.findElementById("com.testerhome.webview:id/button");

Assert.assertTrue(imageButton.isDisplayed());

Set<String> contexts = driver.getContextHandles();

for (String context : contexts) {

// 输出context

logger.info(context);

if (context.contains("WEBVIEW")) {

logger.info("swich_to_content " + context);

driver.context(context);

}

}

logger.info(driver.getContext());

// 隐式等待,针对全局设置

driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

// pageLoadTimeout只能用于webview 或者 pure web

driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);

// 这段代码返回浏览器加载页面状态,complete为加载完成

JavascriptExecutor jse = (JavascriptExecutor) driver;

String status = (String) jse.executeScript("var status=document.readyState;return status");

Assert.assertTrue(status.contains("complete"));

WebDriverWait wait = new WebDriverWait(driver, 30);

 

WebElement input = wait.until(new ExpectedCondition<WebElement>() {

@Override

public WebElement apply(WebDriver driver) {

return driver.findElement(By.xpath("//input[@id='index-kw']"));

}

});

input.sendKeys(keyword);

By by = By.xpath("//button[@id='index-bn']");

if (isElementPresent(by)) {

driver.findElement(by).click();

}

 

driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);

driver.navigate().refresh();

// 返回native app context

driver.context("NATIVE_APP");

MobileElement title = driver.findElementById("android:id/action_bar_title");

Assert.assertTrue(title.getText().contains(keyword));

MobileElement back = driver.findElementById("com.testerhome.webview:id/action_back");

back.click();

Assert.assertTrue(title.getText().equals("百度一下"));

 

}

 

/**

* @author young

* @param by

* @return

*/

private boolean isElementPresent(By by) {

try {

driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);

driver.findElement(by);

return true;

} catch (NoSuchElementException e) {

return false;

}

}

 

@AfterMethod(alwaysRun = true)

public void tearDown() throws Exception {

logger.info("quit");

driver.quit();

}

}

  

总结

可以看出,在Native的APP里面,不许要设置等待相关,Appium会自动等待元素出现。在Web 或WebView,设置和Selenium一样,有几个方法是只能在WebView下使用的,比如wait for page load 和执行JS代码

driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
        // 这段代码返回浏览器加载页面状态,complete为加载完成
        JavascriptExecutor jse = (JavascriptExecutor) driver;
        String status = (String) jse.executeScript("var status=document.readyState;return status");
        Assert.assertTrue(status.contains("complete"));