1. 程式人生 > >UI層自動化測試框架(二):Appium基礎

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();
    }

}

參考資料