Appium.appの使い方（各種設定、Inspector機能について）

# はじめに

このページは、**Appium** を使用してiOS/Androidのテストを書く際の流れについてまとめた記事です。
とくに、Appiumの特徴でもある **Appium.app** の **Inspector機能** を使用した、**アプリの構造解析方法** にフォーカスを当てて説明していきたいと思います。
　
# テストを書く流れ

Appiumを使用したiOS、Androidアプリのテストは、大まかに下記の流れで作成します。

1. **アプリのバイナリ** （iOSの場合は`app`または`ipa`、Androidの場合は`apk`ファイル）を用意する  
または、実機を使用する場合はあらかじめアプリを端末にインストールしておく  
1. **Appium.app** の **Inspector** 機能を使用して、実際にアプリを操作しながら必要な画面要素を調査する
1. 調査した情報をもとに、お気に入りの言語（Java, Ruby, Python...）でテストスクリプトを書く

>**使用可能なアプリのバイナリについて**
Appiumでは、iOSの場合、使用するアプリは **Developmentのプロビジョニングプロファイル** でビルドされた、いわゆる **開発用** のアプリである必要があります。 **Relese用** のアプリはもちろんのこと、 **AdHoc用** に配布されたもの、 **Enterprise用（企業向け）** のものは使用できないので注意が必要です。
※これはAppiumの制限というよりも、Appiumが内部で使用している **UIAutomationの仕様** です。

>その点、Androidの場合はそういった制限がありませんので、例えば **Google Playからインストールしたアプリ** をそのままAppiumでテストすることも可能です。

　
# Appium.app（GUI）を使う

![Appium_GUI_Top.png](https://qiita-image-store.s3.amazonaws.com/0/43533/0d4859bd-3cf3-1a94-10cb-49f89d655718.png)

**Appium.app** は、それ単体でAppiumサーバの起動/終了をしたり、iOS/Androidアプリの構造解析ができるMac用のGUIアプリケーションです。

iOS/Androidのテストを書く際には、アプリ画面の要素（ボタンやテキストフィールド）の情報（IDや階層情報）が必要になるため、都度、実際のアプリを操作しながら、この`Appium.app`を使用して要素を調べていきます。

## Appium.appの入手方法
Appiumの[公式サイト](http://appium.io/)または[GitHub](https://github.com/appium/appium/releases)から、dmgファイル（appium-xxx.dmg）をダウンロードします。
※ 公式サイトよりGitHubの方が更新ペースが早いようです。
ダウンロードしたファイルはダブルクリックしてマウント後、`Applications`フォルダにコピーします。

## 初期設定

**Appium.app** をダブルクリックして起動したら、 **iOS** または **Android** アイコンのボタンをクリックして各種設定を行います。
設定する箇所は、 **シミュレータを使用する場合** と **Macに接続された実機を使用する場合** とで一部異なります。

**iOSの場合**

| 設定項目 | 説明 | 設定例 | (シミュレータ) | (実機) |
|:-----------|:------------|:------------|:------------:|:------------:|
| App Path | appまたはipaファイルの絶対パスを指定 | /Users/kzm/work/app/MyApp.app | ○ |  |
| BundleID | アプリの識別子を指定 | com.example.myapp |  | ○ |
| Force Device | 機種名を指定 | iPhone 5s | ○ | ○ |
| Platform Version | OSバージョンを指定 | 7.1 | ○ | ○ |
| UDID | 端末のUDIDを指定 | 887gpwqs9sd2jhd30r78934020gdj20dge89s9kz |  | ○ |
| Full Reset | 端末のUDIDを指定 | 887gpwqs9sd2jhd30r78934020gdj20dge89s9kz |  | ○ |

　
**Androidの場合**

| 設定項目 | 説明 | 設定例 | (シミュレータ) | (実機) |
|:-----------|:------------|:------------|:------------:|:------------:|
| App Path | apkファイルの絶対パスを指定 | /Users/kzm/work/app/MyApp.apk | ○ |  |
| Package | ※ 後述 | com.example.myapp |  | ○ |
| Launch Activity | ※ 後述 | .main.ToMainActivity | ○ | ○ |
| Platform Name | プラットフォームを指定 | Android | ○ | ○ |
| Automation Name| 使用する自動化ツールを指定 | Appium | ○ | ○ |
| Platform Version | OSバージョンを指定 | 4.4 KitKat (API Level 19) | ○ | ○ |
| Device Name| 機種名を指定 | Android Emulator | ○ | ○ |


**※ PackageとActivityの調べ方**

**【方法①】apkファイルから調べる**

1. [AXMLPrinter2.jar](https://android4me.googlecode.com/files/AXMLPrinter2.jar)をダウンロードして任意のフォルダに格納しておく
1. アプリのバイナリの拡張子を **apk** から **zip** に変更して展開
1. 展開したフォルダ内の **AndroidManifest.xml** ファイルを **AXMLPrinter2.jar** と同じディレクトリにコピー
1. ターミナルで以下のコマンドを実行  
`java -jar AXMLPrinter2.jar AndroidManifest.xml`
1. 出力された結果の以下の箇所を参照する  
**manifestセクション**  
`package="com.example.myapp"`  
**activityセクション**  
`android:name=".main.ToMainActivity"`

　
**【方法②】端末にインストールされたアプリから調べる**

事前準備：MacにAndroid端末を接続し、対象のアプリを起動しておく

* インストール済みのパッケージ一覧を取得するコマンド

```:パッケージ一覧を取得
adb shell pm list packages
```

```:パッケージ一覧を取得（nttdocomoでフィルタリング）
adb shell pm list packages nttdocomo
```

* 現在起動しているActivityを調べるコマンド

```:Activityを調べる
adb shell dumpsys activity | grep "android.intent.category.LAUNCHER.*<パッケージ名>"
```

例えばFacebookアプリの場合、コマンドを実行すると下記の情報が取得できます。

```:FacebookアプリのActivity
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 pkg=com.facebook.katana cmp=com.facebook.katana/com.facebook.nodex.startup.splashscreen.NodexSplashActivity }
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 pkg=com.facebook.katana cmp=com.facebook.katana/.LoginActivity bnds=[0,498][270,837] }
```

この例では以下の箇所がActivityになります。

```
cmp=com.facebook.katana/.LoginActivity
```

実際にAppiumの`Launch Activity`に設定する際は、上記値からパッケージ名を除いた **.LoginActivity** の部分を指定します。

なお、Activityの取得は **アプリをタスクマネージャから完全に終了した状態から起動した直後** に行います。
アプリによっては複数のActivityが表示される場合がありますが、その場合は名前で判断しましょう。

　
## Inspectorでアプリの構造を解析

### 起動方法
設定が完了したら、 **Launch** ボタンをクリックしてAppiumサーバを起動します。

既にターミナルからAppiumサーバを起動済みの場合は、一旦終了してからLaunchボタンで再度起動しましょう。

```:Appiumサーバを終了
killall -9 node
```

下記のようなログが出力されたら準備完了です。

```:Appiumサーバ起動時のログ
info: Welcome to Appium v1.3.1 (REV 1160ce02bb89c354cb99317985123acf39f0e7d3)

info: Appium REST http interface listener started on 0.0.0.0:4723
info: [debug] Non-default server args: {"app":"/Users/kzm/work/app/MyApp.app","deviceName":"iPhone 5s","defaultCommandTimeout":7200}
info: Console LogLevel: debug

info: --> GET /wd/hub/status {}

info: [debug] Responding to client with success: {"status":0,"value":{"build":{"version":"1.3.1","revision":"1160ce02bb89c354cb99317985123acf39f0e7d3"}}}

info: <-- GET /wd/hub/status 200 5.250 ms - 104 {"status":0,"value":{"build":{"version":"1.3.1","revision":"1160ce02bb89c354cb99317985123acf39f0e7d3"}}}
```

**虫眼鏡** ボタンをクリックしてInspectorを起動します。

Inspectorを起動すると、同時にシミュレータまたは端末上で自動的にアプリが立ち上がります。

## 使い方

![Appium_Inspector.png](https://qiita-image-store.s3.amazonaws.com/0/43533/7c439e47-547d-7bc6-cdb2-ecaafecb8e05.png)

Inspector内に表示されているアプリのスクリーンショットをマウスでクリックすると、選択した要素の情報が `Details` エリア内に表示されます。

下記はiOS、Androidアプリでテキストフィールドの情報を取得した際の例です。

```yaml:iOSの場合
name: login_username
type: UIATextField
value: メールまたは携帯番号
label: 
enabled: true
visible: false
valid: true
location: {5, 124}
size: {315, 44}
xpath: //UIAApplication[1]/UIAWindow[1]/UIATableView[1]/UIATableCell[1]/UIATextField[1]
```

```yaml:Androidの場合
content-desc: 
type: android.widget.EditText
text: メールまたは携帯番号
index: 1
enabled: true
visible: true
location: {96, 667}
size: {888, 120}
checkable: false
checked: false
focusable: true
long-clickable: true
package: com.example.myapp
password: false
resource-id: com.example.myapp:id/login_username
scrollable: false
selected: false
xpath: //android.widget.LinearLayout[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]/android.widget.EditText[1]
```

　
上記の **name** (iOSの場合) や **resource-id** (Androidの場合) が、HTMLでいう **id** や **class** に該当します。
ただし通常、テストの自動化を考慮していないアプリではこれらの値は設定されていないケースが多いため、その場合は　**type** や **xpath** を使用して要素を特定することになります。

　
ちなみにiOSではアプリを開発する際、要素に **accessibilityIdentifier** または **accessibilityLabel** を設定しておくことで、Appiumから **name** として値が取得できるようになります。

また、accessibilityIdentifierを明示的に設定していなくても、例えば **UITableCell** は **text** プロパティに設定された文字列がそのまま **name** に設定されます。

　
このように、たとえAppiumでUIテストを行うことを予め想定して開発していなくても（意識的にIDを振っていなくても）、iOS/AndroidアプリのUIテストを自動化することは十分可能です。