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)
# 安裝方式
# 使用方式