---
tags: UiTest
---
# Appium Run iOS UI Test on Mac OS
Appium是一個開放的自動測試框架,透過WebDriver協議,可以跨平台驅動iOS、Android、Windows。使用Appium支援的語言編寫測試碼,透Http request 發送請求給Appium server,然後server在打這些請求打包成語言平台測試架構的語法,部署在Device上執行。以下是原理圖:

## Appium環境部署
**Server**
首先安裝Appium server,最快的方法則是透過Appium官網進行GUI工具安裝。
https://github.com/appium/appium-desktop/releases/tag/v1.22.3-4
根據以上網址,點擊進去後再選擇是適合的檔案進行安裝即可。
但因為Appium1.0已於2022/01/01不在維護,如果要使用Appium2.0請直接參考下方相關步驟。
**Client**
再來就是Client的安裝,基本上透過以下指令即可。**但如果要使用Pycharm進行腳本開發,Appium-Python-Client則可以直接在Preferences頁面中進行安裝設定。**
```
pip3 install appium-Python-Client
```
但在這一步我遇到一點問題,首先是pip在我的mac裡原先就有安裝,但是因為版本是9.0.3,在執行時提示我需要先將pip進行upgrade(這裡大在說明一下pip是什麼,簡易的來說pip就是一個軟體安裝管理包,它可以安裝及管理其他的函式庫裡面的資料,通常只要安裝新版的python都會一起含在裡面)。因此我需要先透過以下command將pip進行升級
```
python3 -m pip install --upgrade pip
```
完成後可以嘗試看看透過以下command確認一下pip的版本
```
pip --version
```
確認已經升級後,就可以直接執行剛剛上面提到安裝Client的命令,完成結果如下:

**Carthage**
iOS測試還需要Carthage,它是一款iOS項目依賴管理工具,與 Cocoapods 有著相似的功能,可以幫助你方便的管理三方依賴,WebDriverAgent 本身使用了 Carthage 管理項目依賴,因此需要提前安裝 Carthage。
```
brew install carthage
```
**libimobiledevice**
libimobiledevice就如同android的adb,如果沒有安裝,Appium 會無法連線到 iOS Device
```
brew install libimobiledevice --HEAD
```
但是我執行完後卻發生以下問題:

在一翻搜尋後,在這裡找到其他的安裝方法:
https://macappstore.org/libimobiledevice/
根據裡面的command進行安裝
```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
```
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
```
```
brew install libimobiledevice
```

**node(原本我的mac已經有安裝,但還是記錄一下需要安裝的東西)**
安裝 node:Appium 本身是由 node.js 開發的,所以需要安裝 node,安裝後也會自動安裝了 npm (npm 全名是 node package manager,就是套件管理工具)
```
brew install node
```
**appium-doctor**
安裝 appium-doctor:驗證 Appium 環境
```
npm install appium-doctor -g
```
**Appium Client(非必要)**
```
sudo npm install wd
```
## 驗證Appium環境
可以透過以下Command確認執行環境是否完善:
```
appium-doctor --ios
```

主要還是先確認必要的工具是否已經有完成安裝即可,下方可選的工具就依據需求再進行安裝。
## WebDriverAgent
簡稱WDA,WDA是一個WebDriver兼容的服務器,Appium主要是透過XCUITest對iOS進行自動化測試,而對XCUITest溝通則是透過WDA來進行,以下是Appium官方提供的WDA載點:
https://github.com/appium/WebDriverAgent
下載下來後用xcode打開,開啟後點開WevDriverAgent.xcodeproj,設定開發者憑證以及將Scheme選擇WebDriverAgentRunner後,接著點選上方工具列中的Product -> Test,如果能在模擬器或是測試器上面看到有安裝WebDriverAgent,就代表完成。

## XCode模擬器設定
要在模擬器中執行APP的測試首先:
1. 要先於模擬器中執行過WebDriverAgent
2. 要先安裝要測試的APP
以下是在模擬器中開啟要測試APP的設定內容
```=python
from appium import webdriver
if __name__ == '__main__':
// 被測試專案中.app的路徑
app = ('/Users/roypan/ios_work/UITestProject/build/Release-iphonesimulator/UITestProject.app')
desired_caps = {
'platformName': 'iOS',
'automationName': 'XCUITest',
'deviceName': 'iPhone 14 Pro', //模擬器名稱
'bundleId': 'com.roy.UITestProject',
"noReset": "true",
"autoAcceptAlerts": "true",
'app': app
}
driver = webdriver.Remote('http://127.0.0.1:4723', desired_caps)
```
在專案中.app的路徑可以透過以下方式取得:
```
xcodebuild -showsdks
```
會顯示正在使用的模擬器版本:

接著再執行以下命令:
```
xcodebuild -sdk iphonesimulator16.0
```
你會在以下內容中找到.app的位置:

另一方面也可以直接透過從專案中直接複製.app檔到自己指定的位置,以避免xcode在build專案中可能產生檔案位置變動的問題,缺點就是在每次app的修改後,要記得將.app檔複製過去即可。


## Find Element
一般最快的方法則是透過"name"或是"class name"來找element,如下所示:
```=python
//透過NAME找element
element = driver.find_element(AppiumBy.NAME, value)
//透過CLASS_NAME找element
element = driver.find_element(AppiumBy.CLASS_NAME, value)
//以此類推...
```
這個name就是在storyboard中每個view的Identifier設定:

## Element Click
```=python
element.click()
```
## TypeTextField Input Text
```=python
element.send_keys("123123")
```
## Find Cell From TableView by SubString
我發現TableView在Appium中,每個Cell的文字內容都可以拿來當作是搜尋的條件,透過Appium Inspector可以看到一個Cell就算是透過多個Static Text元件所組成,所有的文字內容都會被當成該Cell的Name。

所以在找到指定的Table後,可以利用以下function以指定的關鍵字去找到對應的Cell。
```=python
def find_cell_from_table_view_by_sub_string(table_view: WebElement, cell_content: str) -> WebElement:
table_cells: List[WebElement] = table_view.find_elements(AppiumBy.CLASS_NAME, "XCUIElementTypeCell")
for cell in table_cells:
cell_text: str = cell.text
if cell_text.find(cell_content) != -1:
return cell
```
值得注意的一點是,當畫面如果因為自動化操作而有變化,例如點擊了ckeckBox而改變其狀態,就必須要重新搜尋一次在對其進行操作,不然會顯示錯誤。
```=python
sign_table = driver.find_element(AppiumBy.CLASS_NAME, "XCUIElementTypeTable")
cell = find_cell_from_table_view_by_sub_string(sign_table, "(61734002)")
cell.click()
# 因為剛才點擊而造成畫面有變化,所以要重新搜尋
sign_table2 = driver.find_element(AppiumBy.CLASS_NAME, "XCUIElementTypeTable")
cell2 = find_cell_from_table_view_by_sub_string(sign_table2, "(61734000)")
cell2.click()
```
執行後的結果如下:

## 關閉APP
```=python
driver.terminate_app("com.your.bundleId")
```
## PyCharm
Pycharm是撰寫python的IDE工具,也可以透過這工具在專案中安裝Appium-Python-Client或是控制版本等等。

## Appium 2.0
透過Appium2.0的[GitHub](https://https://github.com/appium/appium)文件中的說明可以發現,Appium 1.0 已於2022/01/01停止更新,接下來所更新driver不在兼容Appium1.0,需要2.0才能夠運作,為了以後長久的測試之路可以維持下去,我們只能將appium升級成2.0。
1. 首先先移除掉appium server GUI。
2. 透過以下command安裝Appium 2.0
```
npm install -g appium@next
```
3. 安裝xcuitest deiver
```
appium driver install xcuitest
```
## 啟動Appium Server 2.0
因為Appium 2.0 尚未提供GUI工具,所以目前只能先透過Command來進行啟動。
```
appium
```
## 參考文獻
https://chiahsien.github.io/post/how-to-use-appium-to-test-ios-app/
https://hackmd.io/@5BMTzZwzQxGZneWokjHzoQ/S1aHMQbzs