iOS & Android UI 自動化測試使用說明 === ## 目錄 [TOC] ## 工具介紹 對於 iOS 以及 Android 會使用不同的工具,但是程式可以撰寫在一起 ### 1. Python 一種可讀性高的程式語言,至少有一個 main.py 就可以執行了 ```python import foo def foo_function(args): print(args) return 'foo' if __name__ == “__main__”: print(foo_funcion('a')) ``` 印出來的結果會是 ``` a foo ``` ### 2. Appium Desktop 用於連結 iOS/Android 手機,查看 APP 元件的以及簡易錄製腳本的工具 ![](https://i.imgur.com/uE4OHC7.png) [下載連結](https://github.com/appium/appium-desktop/releases) ### 2. Web Driver Agent (WDA) 在iOS客戶端實現了一個 WebDriver 的 Server,借助這個 server,可以控制iOS設備進行測試。 ![](https://i.imgur.com/AWUXtzr.png) [Appium](http://appium.io/) 基於 [FacebookArchive](https://github.com/facebookarchive) 的 [WebDriverAgent](https://github.com/facebookarchive/WebDriverAgent) 發展出可讓 iOS 使用 Appium Desktop 查看元件的 WebDriverAgent ### 4. UIAutomator2 > UIAutomator 是 Google 提供的用來做 Android 自動化測試的一個Java庫。可以對 APP 內的任意一個元件,並對其進行任意操作,但有兩個缺點:1. 測試腳本只能使用Java語言 2. 測試腳本必須每次被上傳到設備上運行。 [openatx](https://github.com/openatx) 基於 [UIAutomator](https://developer.android.com/training/testing/ui-automator) 發展出可用 Python 的 [UIAutomator2](https://github.com/openatx/uiautomator2),並開發了其他新功能 1. 加入了 [openstf/minicap](https://github.com/openstf/minicap) 達到實時屏幕投頻,以及實時截圖 2. 加入了 [openstf/minitouch](https://github.com/openstf/minitouch) 達到精確實時控制設備 ## 環境設置 ### 前置環境 1. Python >= 3.5.0 [下載並安裝](https://www.python.org/downloads/) 2. Java 1.8 [下載並安裝](https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) ![](https://i.imgur.com/RHzaGR2.png) 2. 安裝 Nodejs [下載並安裝](https://nodejs.org/en/) 3. 下載 Appium 需要使用 CLI 來安裝 1. 打開 cmd/Terminal 2. 輸入 ```npm -v```, 如顯示版本號,表示 Nodejs 可以使用 3. 輸入 ```npm install -g appium``` 進行安裝 4. 輸入 ```npm install -g appium-doctor``` 進行安裝 3. 安裝 Android Studio [下載並安裝](https://developer.android.com/studio) 6. (Mac) Homebrew [相關安裝教學](https://diary.taskinghouse.com/posts/4766365-homebrew-essential-mac-suite-management-tools/) 7. pip 安裝方式 打開 cmd/Terminal 輸入指令進行安裝 ```shell pip install XXX ``` 或者用 txt 檔案直接安裝相關函式庫 ```shell pip instal requirement.txt ``` requirement.txt ``` yaml wda weditor uiautomator2 appium ``` ### Android (Windows) 環境設置步驟 1. 安裝 pip 套件 a. UIAutomator2 b. WEditor c. yaml d. appium-python-client ### iOS (Mac) 測試環境設置步驟 1. 安裝 pip 套件 a. wda b. appium ### 連結 Android 步驟 ### 連結 iOS 步驟 ## 驗證方式 (簡易) ### 判斷元件是否存在 ```python a = elementA.exists assertEqual(a, True) ``` ### 判斷文字是否正確 ```python a = elementA.getText assertEqual(a, "泉州市") ``` ### 判斷元件內的子元件數量 ```python a = elementA.getChild assertEqual(a, 6) ``` ## 程式說明 (簡易) 導入需要的函式庫 ```python= import unittest # Python 单元测试框架 import yaml # 讀取 yaml 格式檔案 import wda # 用於控制 iOS APPS import time # 用於暫停程式,等待手機 UI 或資料載入執行完成 from selenium import webdriver from appium import webdriver from conf.appium_config import appium_start # 導入用於啟動 appium 連結手機的程式 import uiautomator2 as u2 # 用於控制 Android APPS ``` 定義單元測試的 cycle 前後的動作 ```python=+ class Youbike(unittest.TestCase) { #測試前啟動 WebDriver,連結手機 @classmethod def setUpClass() {} #測試成功登入 def test_login_success() {} #測試失敗登入 def test_login_failed() {} #測試後斷開手機,關閉 WebDriver @classmethod def tearDownClass() {} } ``` 主程式與副程式 ```python=+ # 任務 def suite(): tests = ["test_login_success", "test_login_failed"] return unittest.TestSuite(map(Youbike,tests)) # 主要執行 if __name__ == "__main__": unittest.TextTestRunner(verbosity=2).run(suite()) ``` ## Command Line ### ADB #### 1. 查詢目前接上電腦的 Android 手機 id ```shell adb devices ``` 顯示結果: ``` List of devices attached 420098eacaa8b4c3 device ``` 更多可參考 [Android adb tool 功能整理 - huenlil](https://huenlil.pixnet.net/blog/post/23271843-android-adb-tool-%E5%8A%9F%E8%83%BD%E6%95%B4%E7%90%86) ### XCode ## 注意事項 1. 使用 XCode 安裝到 iPhone/iPad 需要到手機的 Setting > General > Profile, 對帳號進行信任 授權。 ## Test Case yaml 文件撰寫 登入範例 Example: ```yaml test_case: # step1 - info: 點擊會員登入 selector: - text: 會員登入 clickable: True - action: - screenshot: /tmp - setText: "1234567" - clearText error_message: 應該存在側邊欄按鈕 ``` ## Steps - info: 介紹 Steps - pre: - fixed function (other py file) - nologin - login - sleep: 4 #second - selector (findElement) - `text`, `textContains`, `textStartsWith` (String) - `className` (String) - `description`, `descriptionContains`, `descriptionStartsWith` (String) - `checkable`, `checked`, `clickable`, `longClickable` (Boolean) - `scrollable`, `enabled`, `focusable`, `focused`, `selected` (Boolean) - `packageName` (String) - `resourceId` (String) - `index`, `instance` (int, 還不清楚兩個怎麼分辨使用) - `xpath` (String, 用了 xpath 不可用其他 selector) - siblings (Optional, Advance, findElement) - 與 selector 相同 - child (Optional, Advance, findElement) - 與 selector 相同 - child_by_text (Optional, Advance, findElement, 可以找到第三層的文字) - target: (String) - `className` (String) - `description`, `descriptionContains`, `descriptionStartsWith` (String) - `checkable`, `checked`, `clickable`, `longClickable` (Boolean) - `scrollable`, `enabled`, `focusable`, `focused`, `selected` (Boolean) - `packageName` (String) - `resourceId` (String) - `index` (int) - position (Optional) - right/left/up/down: - `className` (String) - `description`, `descriptionContains`, `descriptionStartsWith` (String) - `checkable`, `checked`, `clickable`, `longClickable` (Boolean) - `scrollable`, `enabled`, `focusable`, `focused`, `selected` (Boolean) - `packageName` (String) - `resourceId` (String) - `index`, `instance` (int, 還不清楚兩個怎麼分辨使用) - action (順序) 動作,不回傳值 - `click()` - `long_click()` - `screenshot` (filePath: String) - `swipe`: (right/left/up/down) - `clear_text` 動作,輸入 (only input) - `set_text`: (String) - `scroll`: - to `scroll().to(...)`: - `className` (String) - `description`, `descriptionContains`, `descriptionStartsWith` (String) - `checkable`, `checked`, `clickable`, `longClickable` (Boolean) - `scrollable`, `enabled`, `focusable`, `focused`, `selected` (Boolean) - `packageName` (String) - `resourceId` (String) - `index`, `instance` (int, 還不清楚兩個怎麼分辨使用) - normal `scroll()` 去值 - `get_text` - `center` - `exists`: (Boolean) - `validate`: (String) - error_message: (String) # 安裝方式 # 使用方式