如何玩轉app+webview混合應用自動化
WebView簡介
移動平臺的一個特性是能夠將“ 無 格式 ” Web瀏覽器嵌入“ 原生 ”應用程式中,這些應用程式稱為“ webviews ”。Android開發人員使用“ android.webkit.WebView ”類在應用程式內部實現webview。類層次結構如下所示
java.lang.Object繼承
android.view.View
android.view.ViewGroup
android.widget.AbsoluteLayout
android.webkit.WebView
我們可以說,在一行中,混合應用程式是包含原生檢視和Web檢視的應用程式。
Appium的 一個主要原則是提供appium優於Calabash自動化工具的優勢,在Appium中,不需要更改被測試的應用程式。我們自動化同樣的應用程式進入生產。Appium允許我們使用Chromedriver內建的支援來測試WebApps和混合應用程式。我們可以使用selenium webdriver現有方法來自動化webview的
檢查WebView元素的條件
我們可以使用Chrome DevTools來除錯和檢查Android應用程式中的WebView內容。
- 它需要Android 4.4或更高版本,即API級別> = 19。
- 應啟用WebView除錯; 開發人員必須在WebView類中啟用“ setWebContentsDebuggingEnabled ”標誌。此標誌可以除錯載入到應用程式的任何WebView中的Web內容(HTML / CSS / JavaScript)。
- 桌面和Android裝置上安裝版本為32或更高版本的Chrome瀏覽器和DESKTOP_ANDROID_CHROME_BROWSER_VERSION> = ANDROID_DEVICE _CHROME_BROWSER_VERSION
- 除此之外,只有在應用程式內啟用webview除錯時,Appium才會識別WebView上下文。我們可以在LOLLIPOP / KITKAT Android裝置上檢查webview 。
- Appium還使用Selendroid在4.4以上的裝置上支援webview。要使用appium的此功能,必須在傳遞給Appium伺服器的所需功能中將“automationName”指定 為“selendroid” 。如果我們測試的混合應用程式是以支援最低Android版本4.0.4(API級別14)和最高Android版本4.3(API級別18)的方式構建的,那麼我們可以檢查webview元素並使用selendroid模式執行我們的自動化測試appium。
如何在混合應用程式中檢查和自動化WebView
令人遺憾的是UIAutomatorViewer無法幫助我們檢查WebView下的元素。
我們可以通過兩種方式檢查WebView下的這些元素:
使用Selendroid Inspector
使用Appium通過執行具有所需能力appium工具automationName 為“ Selendroid ”只適用於應用,其是建立Android版本<4.4
我們將使用appium伺服器手動啟動應用程式:
1)瀏覽apk以從本地資料夾啟動。
2)選擇所需的能力automationName 作為“ Selendroid ”和其他強制引數,如platformname,platformversion, launch活動
3)單擊“播放”按鈕啟動伺服器
4)應用程式啟動。如果我們仔細檢視Appium伺服器執行日誌,那麼我們可以看到它在埠8080的本地主機上啟動selendroid伺服器
5)如果selendroid伺服器正常啟動然後點選URL以下它將返回到json字串下面
URL:http:// localhost:8080 / wd / hub / status
jSON字串:{“value”:{“supportedApps”:[],“build”:{“browserName”:“selendroid”,“version”:“0.12.0”},“os”:{“arch”:“ armeabi-V7A”,”版本”:” 19“,”姓名”:”機器人”},” supportedDevices”:[]},”狀態”:0}
5)要開始檢查應用程式,我們點選此URL http:// localhost:8080 / inspector它將自動重定向到http:// localhost:8080 / inspector / session / 88ce8684-d785-4a24-9157-80967becc60d /取得會話ID如果selendroid伺服器正在執行,現在我們可以選擇檢查應用程式元素,所以我們所做的是:
- 我們點選了一個帶有我們從selendroid檢查器獲取的id的按鈕,它導航我們到webview,它還為點選操作生成了等效的Java程式碼。
- 我們看到按鈕點選webview出現,selendroid檢查員生成完成webview的html源。再次像在步驟1中一樣,如果我們在文字框上執行單擊操作,按鈕,選擇下拉列表會生成等效的Java程式碼。
使用Chrome遠端偵錯程式
僅適用於支援Android版本4.4+或API級別> 18的應用程式。需要注意的重要一點是appium適用於API級別> 17但是chrome遠端偵錯程式適用於API級別> 18,即我們可以將此chrome功能用於API級別> 18
1)在chrome瀏覽器中輸入“ chrome:// inspect /#devices ”
2)在使用adb列出的裝置中開啟啟用了webview偵錯程式的應用程式
3)點選檢查連結,我們可以檢查webview下的元素。
檢查電子郵件文字輸入欄位
檢查密碼輸入文字欄位
檢查登入提交按鈕欄位
編寫指令碼以自動化WebView
我們可以按照以下4個步驟自動化Webview
- 導航到您的應用中Web檢視處於活動狀態的部分
- 呼叫getContext()方法,該方法將返回我們可以訪問的上下文列表,例如'NATIVE_APP'或'WEBVIEW_1'
- 使用我們想要訪問的上下文的id呼叫context()方法,即WEBVIEW_1,它是應用程式的webview上下文的名稱。這將Appium會話置於一種模式,其中所有命令都被解釋為用於自動化Web檢視,而不是比應用程式的本機部分。例如,如果執行getElementByTagName,它將在Web檢視的DOM上執行,而不是返回UIAElements / MobileElements / Native WebElements。
- 要停止在Web檢視上下文中自動化,我們可以使用id NATIVE_APP(即應用程式的名稱本機上下文)再次呼叫上下文。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
package Appium; import org.testng.annotations.Test; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import io.appium.java_client.android.AndroidDriver; import io.appium.java_client.AppiumDriver; import java.net.MalformedURLException; import java.net.URL; import java.util.Set; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.Select; import org.openqa.selenium.support.ui.WebDriverWait;
public class WebViewSelendroidApp { public static AndroidDriver<WebElement> driver; public static AppiumDriver<WebElement> _driver; public static DesiredCapabilities cap = new DesiredCapabilities();
@BeforeTest public void startAppium() throws MalformedURLException, InterruptedException{ System.out.println("setUP() :: driver.AndroidDriver() executed"); cap.setCapability("platformVersion","4.4.4"); cap.setCapability("platformName","Android"); cap.setCapability("deviceName","ZX1B32HNBD"); cap.setCapability("app","C:\\Users\\WebView-test.apk"); driver = new AndroidDriver<WebElement>(new URL("http://127.0.0.1:4725/wd/hub"),cap); }
@Test public void AppLogin() throws InterruptedException{ System.out.println("AppLogin() :: driver.start() executed"); By webView = By.className("android.webkit.WebView"); By title = By.id("android:id/title"); WebDriverWait wait = new WebDriverWait(driver,300); driver.findElement(title).getText(); Set<String> availableContexts1 = driver.getContextHandles(); System.out.println("Total No of Context Found Before reaching WebView = "+ availableContexts1.size()); System.out.println("Context Name is "+ availableContexts1);
//4.1 Navigate to a portion of your app where a web view is active driver.findElement(By.id("com.mkyong.android:id/buttonUrl")).click(); wait.until(ExpectedConditions.visibilityOfElementLocated(webView)); // 4.2 Call getContext() method which will returns a list of contexts we can access, like 'NATIVE_APP' or 'WEBVIEW_1' Set<String> availableContexts = driver.getContextHandles(); System.out.println("Total No of Context Found After we reach to WebView = "+ availableContexts.size()); for(String context : availableContexts) { if(context.contains("WEBVIEW")){ System.out.println("Context Name is " + context); // 4.3 Call context() method with the id of the context you want to access and change it to WEBVIEW_1 //(This puts Appium session into a mode where all commands are interpreted as being intended for automating the web view) driver.context(context); break; } } String input_box_text = driver.findElement(By.id("name_input")).getAttribute("value"); System.out.println("Pre written text inside text box is " + input_box_text); driver.findElement(By.id("name_input")).clear(); driver.findElement(By.id("name_input")).sendKeys("Amit Jain"); System.out.println("No of dropdown on page "+ driver.findElements(By.xpath("//select")).size());
int size=driver.findElements(By.xpath("//select")).get(0).findElements(By.xpath("//option")).size(); System.out.println("No of Elements in dropdown "+ size); WebElement car = driver.findElement(By.name("car")); Select preferedCar=new Select(car); preferedCar.selectByIndex(2); System.out.println("Button Value is : " + driver.findElement(By.xpath("/html/body/form/div/input[2]")).getAttribute("value")); //Key code constant: Back key. //Constant Value: 4 (0x00000004) driver.sendKeyEvent(4); // 4.4 To stop automating in the web view context we can simply call the context again with id NATIVE_APP. for(String context : availableContexts) { if(context.contains("NATIVE")){ System.out.println("We are Back to " + context); driver.context(context); if (driver.findElement(title).getText().equals("WebViewApp")) System.out.println("Context Switched"); } } }
@AfterTest(alwaysRun= true) public void tearDown(){ driver.quit(); System.out.println("tearDown() :: driver.quit() executed"); } } // end of class |