UI層自動化測試框架(二):Appium基礎
申明:本章節引用很多第三方資料和網上的教程,在參考資料tab中我都有備註,請理解。
由於該框架是基於Appium的,所以先講講appium的基礎知識
一:Appium介紹
Appium是由nodejs的express框架寫的Http Server。Appium不是它⾃⼰建立⼀套新的測試框架,是將現有的優秀的框架進⾏了整合,以Selenium WebDriver的協議(JsonWireProtocol/Restful web service)統⼀起來. 使得這個框架滿⾜多⽅⾯的需求。Appium啟動⾃動化測試後,在被測裝置上啟動⼀個server,監聽來⾃Appium server的指令。不同的平臺(如IOS,Android)採⽤不同的運⾏和交換⽅式。Appium將某個樁程式“侵入”平臺,用於接受指令,來完成測試指令碼的執行。
特性:
1. 跨平臺, native hybrid webview(H5)
2. 跨裝置, android iOS
3. 跨app,可以在多個app之間互動
4. 不依賴APP開原始碼( Android 對H5的支援需要程式碼支援,這裡不細說)
5. 支援Selenium WebDriver / Selenium Grid
6. 跨語言, java python ruby nodejs
7. Open Source
二:Appium工作原理
Android端
1.原理圖:
在Android端,appium基於WebDriver,並利⽤用Bootstrap.js,最後通過調⽤用UiAutomator的命令,實現App的自動化測試。UiAutomator測試框架是Android SDK⾃自帶的App UI自動化測試Java庫。另外由於UiAutomator對H5的⽀支援有限,appium引入了chromedriver來實現基於H5的自動化。
2.主要原理:
- 左邊的WebDriver script是我們的selenium測試指令碼
- 中間是起的Appium的服務,Appium在這邊起了一個Server(4723埠),跟selenium Webdriver測試框架類似,Appium⽀支援標準的WebDriver JSONWireProtocol 。在這裡提供了一套web服務,Appium Server接收web driver 標準請求,解析請求內容,調⽤用對應的框架響應操作。如:指令碼傳送一個點選按鈕的請求給appium server
- appium server會把請求轉發給中介軟體Bootstrap.jar ,它是用java寫的,安裝在手機上.Bootstrap 接收appium 的命令(4724埠),最終通過調⽤用UiAutomator的命令來實現
- 最後執⾏行的結果由Bootstrap返回給appium server
- 另外,appium還用到了chromedriver來⽀支援基於H5(webview)的測試
iOS端
1.原理圖:
在IOS端,appium同樣使⽤用WebDriver的⼀一套協議。與Android端測試框架不同的是,appium ios封裝了apple的 Instruments框架,主要用了Instrument裡的UI Automation(Apple的⾃自動化測試框架),然後在裝置中注⼊入bootstrap.js進⾏行監聽。
2.主要原理
- 左邊的WebDriver script是selenium測試指令碼
- 中間是起的Appium的服務,Appium在這邊起了⼀一個Server(4723埠),跟selenium Webdriver測試框架類似,Appium⽀支援標準的WebDriver JSONWireProtocol 。在這裡提供了一套web服務,Appium Server接收web driver 標準請求,解析請求內容,調⽤用對應的框架響應操作。如:指令碼傳送一個點選按鈕的請求給appium server。
- appium server呼叫instruments.js 啟動⼀一個socket server,同時分出⼀一個⼦子程序運⾏行instruments.app,將bootstrap.js(一個UIAutomation指令碼)注⼊入到device⽤用於和外界進⾏行互動
三:安裝Appium
這一部分,其實網上都有非常詳細的教程,這裡就不一一闡述
主要的步驟為:
- 安裝JDK並配置環境變數
- 安裝Android SDK並配置環境變數
- 安裝Nodejs
- 安裝appium
- 驗證安裝
四:DesiredCapabilities
DesiredCapabilities攜帶了一些配置資訊,在啟動session 時必須提供,如啟動模式,apk/app配置,package/activity配置,瀏覽器配置,鍵盤配置。從本質講 是一組 key- value形式的物件 ,你可以理解為java裡的json物件。(你可以在selenium-api-2.49.0- sources.jar 檢視CapabilityType的宣告)
DesiredCapabilities的重要作用是在啟動時傳遞資訊給Appium Server。可以粗略的分為兩類:裝置資訊類和應用資訊類
- 裝置資訊:裝置是真機還是模擬器,手機作業系統以及版本等。
- 應用資訊:要進行瀏覽器測試還是移動端測試,如果是移動應用,安裝apk或者app檔案的路徑,如果是瀏覽器測試,瀏覽器的型別是什麼。
下圖列舉了DesiredCapabilities常用的關鍵字:
Session介紹
Session是指一個在終端使用者與互動系統進行通訊的會話,用於保持狀態的基於web伺服器的方法。將Appium理解為server端,客戶端裝置發起command的必須是在session start後才可以進行的。一般來說,通過post/session這個url,然後傳入DesiredCapabilities就開啟session啦。
DesiredCapabilities的使用:
Android:
DesiredCapabilities caps = new DesiredCapabilities();
// apk地址,不需要安裝的話這行不需要
// File app=new File("C:\\Users\\charlie.chen\\djigo.apk");
// 不需要安裝的話就去掉這個
// caps.setCapability("app", app.getAbsolutePath());
caps.setCapability("platformName", "Android");
caps.setCapability("platformVersion", "6.0");
caps.setCapability("deviceName", "P9");
caps.setCapability("udid", udid);
caps.setCapability("appPackage", appPackage);
caps.setCapability("appActivity", appActivity);
// caps.setCapability(MobileCapabilityType.BROWSER_NAME, "Chrome");
caps.setCapability("unicodeKeyboard", "True"); // 支援中文輸入
caps.setCapability("resetKeyboard", "True"); // 重置輸入法為系統預設
iOS:
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("platformName", "iOS");
caps.setCapability("platformVersion", "9.3");
caps.setCapability("deviceName", "iPhone 6s");
caps.setCapability("unicodeKeyboard", "True");
caps.setCapability("resetKeyboard", "True");
五:元素的定位
UIAutomatorViewer是Andorid SDK自動的一個app元素檢視工具,通過這個工具我們可以檢視app view上面的元素的屬性,然後再利用Appium各個API對元素進行定位操作。
UIAutomatorViewer使用:
- 將測試裝置連線電腦,並且將被測app簽名後安裝在測試機。
- 開啟安裝的SDK資料夾,在sdk/toos下找到uiautomatorviewer.bat,執行
如圖右下方可以看到定位的元素屬性:index,text,id,classname,。。。。
常見的元素定位的方法:
- 通過id定位:
dirver.findElement(By.id("id is me"));
- 通過name定位
dirver.findElement(By.name("name is me")); //name其實就是text
- 通過clssName定位
dirver.findElement(By.className("className is me"));
- 通過xpath定位
dirver.findElement((By.xpath("//android.widget.TextView[contains(@text,'天空之城')]"));
- List遍歷
List<WebElement> textViewList=driver.findElements(By.id("id is me"));
textViewList.get(0).sendKeys("Some Name");
textViewList.get(1).sendKeys("[email protected]");
- 通過座標定位
TouchAction to = new TouchAction(driver);
try {
to.tap(x, y).release().perform();
}
六:一個簡單的指令碼
package com.appium.demo;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import io.appium.java_client.android.AndroidDriver;
import java.io.File;
import java.net.URL;
import java.util.List;
public class AppDemo {
public static void main(String[] args){
private AndroidDriver driver;
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(CapabilityType.BROWSER_NAME, "");
capabilities.setCapability("platformName", "Android");
capabilities.setCapability("deviceName","Android Emulator");
capabilities.setCapability("platformVersion", "4.4");
capabilities.setCapability("app", app.getAbsolutePath());
capabilities.setCapability("appPackage", "com.example.demo");
capabilities.setCapability("appActivity", ".WelcomeAcitvity");
driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
}
WebElement el = driver.findElement(By.name("Add Contact"));
el.click();
List<WebElement> textViewList=driver.findElements(By.id("id is me"));
textViewList.get(0).sendKeys("Some Name");
textViewList.get(1).sendKeys("[email protected]");
driver.findElementByName("Save").click();
driver.quit();
}
}