Appium1.6.xでAppium再入門

「実践Appium」出ましたね、Appium好きなのでAppiumオンリーの本が出たのは個人的にテンション上がります。
しかし書籍の中のAppiumは1.6.0以前のUIAutomationを使ってるものとなってるようです。

iOS10でUIAutomationがdeprecatedになり、Appiumもそれに伴い1.6.0でXCUITestをベースとした形に移行したようで、UIAutomationの代わりにFacebook製のWebDriverAgentになったようです(それについての詳細も今後書けたらいいなと思ってます)

そんなわけで今回は久々にAppiumを動かしてみました。

公式のリポジトリのサンプルコードが実行できるようになるまでの手順と
途中でハマった箇所とその解決方法を載せておきます。

# appiumとは？
すでにQiitaに良い記事が書かれてるので割愛します。
http://qiita.com/k5n/items/899cf40a0021a6a92efd

# 環境構築
公式の通りやっていけば特に問題はないと思います。
この記事ではnodeは`nodebrew`で`v6.6.0`を使っています。
https://github.com/appium/appium

一応コマンドも書いておきます。

```
npm -g install appium
npm -g install appium-doctor
```

今回使ったappiumのバージョンは`1.6.2`です。

## appium-doctor
`appium-doctor`で現在の環境のチェックをし、何か足りないものがあればインストールなりを行ってください。

私の手元で実行するとこんな感じでした。

```
info AppiumDoctor Appium Doctor v.1.2.5
info AppiumDoctor ### Diagnostic starting ###
info AppiumDoctor  ✔ Xcode is installed at: /Applications/Xcode.app/Contents/Developer/
info AppiumDoctor  ✔ Xcode Command Line Tools are installed.
info AppiumDoctor  ✔ DevToolsSecurity is enabled.
info AppiumDoctor  ✔ The Authorization DB is set up properly.
info AppiumDoctor  ✔ The Node.js binary was found at: /usr/local/bin/node
info AppiumDoctor  ✔ Carthage was found at: /usr/local/bin/carthage
info AppiumDoctor  ✔ HOME is set to: $HOME
WARN AppiumDoctor  ✖ ANDROID_HOME is set to '$HOME/android-sdks' but this is NOT a valid path!
info AppiumDoctor  ✔ JAVA_HOME is set to: /Library/Java/JavaVirtualMachines/jdk1.8.0_25.jdk/Contents/Home
WARN AppiumDoctor  ✖ adb could NOT be found at '$HOME/android-sdks/platform-tools/adb'!
WARN AppiumDoctor  ✖ android could NOT be found at '$HOME/android-sdks/tools/android'!
WARN AppiumDoctor  ✖ emulator could NOT be found at '$HOME/android-sdks/tools/emulator'!
WARN AppiumDoctor  ✖ Bin directory for $JAVA_HOME is not set
info AppiumDoctor ### Diagnostic completed, 5 fixes needed. ###
info AppiumDoctor 
info AppiumDoctor ### Manual Fixes Needed ###
info AppiumDoctor The configuration cannot be automatically fixed, please do the following first:
WARN AppiumDoctor - Manually configure ANDROID_HOME.
WARN AppiumDoctor - Manually install adb and add it to PATH.
WARN AppiumDoctor - Manually install android and add it to PATH.
WARN AppiumDoctor - Manually install emulator and add it to PATH.
WARN AppiumDoctor - Add '$JAVA_HOME/bin' to your PATH environment
info AppiumDoctor ###
info AppiumDoctor 
info AppiumDoctor Bye, run appium-doctor again when all manual fixes have been applied!
info AppiumDoctor 
```
Androidについての設定でxが付いてますがiOSだけ動かすのでこれでOKです。


# サンプルコード
今回は以下のappiumのリポジトリにあるサンプルコードを使用します。
`https://github.com/appium/sample-code`

適当なところに`git clone https://github.com/appium/sample-code`しませう。

内容は以下のような構成になってます。

```
sample-code/
├── apps <- サンプルで動かすテストコード集
│   ├── ApiDemos
│   ├── ContactManager
│   ├── RobotCalibration
│   ├── RottenTomatoes.zip
│   ├── RottenTomatoesPageSnapshot.html
│   ├── RottenTomatoesSnapshot.html
│   ├── TestApp
│   ├── ToggleTest
│   ├── UICatalog.zip
│   ├── WebViewApp
│   ├── android-rottentomatoes-demo-debug.apk
│   ├── chromedriver
│   ├── chromedriverWin
│   └── selendroid-test-app.apk
└── examples <- 各言語毎のサンプルコード集
    ├── C#
    ├── RobotFramework
    ├── dotnet
    ├── java
    ├── node
    ├── perl
    ├── php
    ├── python
    └── ruby <- 今回はコレで遊ぶ
```

##rubyのサンプルを動かす

`cd sample-code/sample-code/examples/ruby`でrubyのサンプルプログラムに移動しましょう。
次にrubyのテストをするための各種gemをインストールします。

その前にちょっとGemfileを確認。

```before
source 'https://www.rubygems.org'

gem 'appium_lib',         '~> 6.0.0' <- サンプルの場合appium_libのバージョンが古いみたい
gem 'rest-client',        '~> 1.6.7'
gem 'rspec',              '~> 2.14.1'
gem 'cucumber',           '~> 1.3.15'
gem 'rspec-expectations', '~> 2.14.5'
gem 'spec',               '~> 5.3.4'
gem 'sauce_whisk',        '~> 0.0.13'
gem 'test-unit',          '~> 2.5.5' # required for bundle exec ruby xunit_android.rb
```

appium_libのバージョンが古いので上げておきましょう。

```after
source 'https://www.rubygems.org'

gem 'appium_lib',         '~> 9.0.0'
gem 'rest-client',        '~> 1.6.7'
gem 'rspec',              '~> 2.14.1'
gem 'cucumber',           '~> 1.3.15'
gem 'rspec-expectations', '~> 2.14.5'
gem 'spec',               '~> 5.3.4'
gem 'sauce_whisk',        '~> 0.0.13'
gem 'test-unit',          '~> 2.5.5' # required for bundle exec ruby xunit_android.rb
```

改めてインストール実行です。

```
bundle install
```
※rubyのバージョン管理については`rbenv`で`2.3.3p222`を使いました。`bundler`や`rbenv`のインストール方法はここでは割愛します。

今回はrspecはすっ飛ばしてcucumberで遊びます。

### Desired Capabilities
実行の前にCapabilityの設定も確認して見ましょう。

```
cd ./cucumber_ios/features/support/iphonesim
```

ここには後述する実行時に与えるcapabilitiesのための設定ファイルが配置されています。
`appium.txt`というファイルがあると思うので中身を確認してみましょう。

**注意⚠️** `appium.txt`は`./cucumber_ios/features/support/`直下にもあります。後述するcucumberの実行時のパラメタを指定しない場合は`./cucumber_ios/features/support/appium.txt`の値が採用されます。

```
.
├── appium.txt
├── env.rb
├── ipadsim
│   └── appium.txt
└── iphonesim
    └── appium.txt <- 今回見るのはこっちね。
```

ファイルの中身はtoml形式(https://github.com/toml-lang/toml) で各種キーとその値が定義されています。

では確認してみましょう。

```before
[caps]
platformName = "ios"
deviceName = "iPhone 6"
platformVersion = "8.1"
app = "../../../apps/TestApp/build/release-iphonesimulator/TestApp.app"

[appium_lib]
sauce_username = false
sauce_access_key = false
```

私の実行環境に合わせてちょっと変更します。

```after
[caps]
platformName = "ios"
deviceName = "iPhone 6"
platformVersion = "10.1" <- 8.1 -> 10.1にしただけ
app = "../../../apps/TestApp/build/release-iphonesimulator/TestApp.app"

[appium_lib]
sauce_username = false
sauce_access_key = false
```

`platformVersion`を10.1に変更しました。※後述するトラブルシューティングのエラーが出たため。

この他にもDesired Capabilitiesには色々な設定が定義されていますので一度確認しておくと良いでしょう。
Desired Capabilitiesは
http://appium.io/slate/en/master/?ruby#the-default-capabilities-flag
または
https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md
で確認できます。


##cucumberでの実行

`sample-code/sample-code/examples/ruby/cucumber_ios/`に戻って以下のコマンドを実行します。

```
bundle exec cucumber -p iphonesim
```


```
...
...

2 scenarios (2 passed)
8 steps (8 passed)
4m25.116s

```

無事実行完了です🎉



# トラブルシューティング集
今回のサンプルを動かす上でで引っかかった時に出たエラーメッセージとその解決方法です。

##Appium's IosDriver does not support xcode version 8.1. Apple has deprecated UIAutomation. Use the "XCUITest" automationName capability instead. 
~~capabilitiesに`automationName = "XCUITest"`を追加しましょう。~~
上記の方法でもよかったのですが`appium_lib`のバージョン`9.0.0`からデフォルトがXCUITestになったようで、不要となりました。

##Platform version must be 9.3 or above. '8.1' is not supported
capabilitiesの`platformVersion`の値を変更しましょう。

##Do you want the application “WebDriverAgentRunner-Runner.app” to accept incoming network connections?
iOS側ではなく、MacOSでアプリが通信する際に出るアラートでこれが出る場合がありました。
初回起動時だけかと思ったのですが、毎回このアラートが出てしまいました。
このダイアログはMacOSのfirewallがOnになってると出るため、  
一時的なとしてfirewallをOffにすると当然出なくなりました。誰かもっといい方法あれば教えてください。
※firewallがOnでアラートが出てもテストは問題なく完了するので放置でもいいかな。

## May Slow Down Your iPhone
サンプルのアプリが32bitでビルドしたものを実行してるためです。再ビルドしましょう。
`samples/sample-code/sample-code/apps/TestApp`で以下のコマンドを実行します。
64bitでのビルドのため`-arch x86_64`が必要となります。

```
xcodebuild -sdk iphonesimulator -arch x86_64
```

#要素の特定
テストを書いて実行するとうまく要素が取れない場合などがあります。
そのような場合は`appium-console`を使ってインタラクティブに自分が欲しい要素の特定方法を探る事ができます。


## appium-console
使い方は以下参照
http://appium.io/slate/en/tutorial/ios.html?ruby#starting-the-console

appium-consoleはインストールすると`arc`コマンドが使えるようになります。
サンプルに`sample-code/sample-code/examples/ruby/arc_ios_calc`があるのでこれで動かしてみましょう。
`sample-code/sample-code/examples/ruby/arc_ios_calc/appium.txt`にCapabilityについてのファイルがあります。前述したCapabilityの設定に修正してください。

次に設定ファイルに移動します。

```
cd sample-code/sample-code/examples/ruby/arc_ios_calc
```

次に`arc`コマンドを実行します。

```
arc
```

capabilityファイルが複数ある場合などは以下のように
tomlファイルを指定しましょう；

```
arc toml appium.txt
```

無事起動できたらコマンドを実行して色々と試してみましょう。

###page
`page`コマンドで表示されている画面の要素の一覧を見ることが出来ます。

```
$page
XCUIElementTypeApplication
   name, label: TestApp
   value: 
   hint: 
XCUIElementTypeOther
   name, label, value: 
   hint: 
...
省略
...
XCUIElementTypeOther
   name, label: -100% battery power
   value: 
   hint: 
nil

```


###page_class
`page_class`を実行するとページを構成するクラスとその数を表示します。

```
$page_class
7x XCUIElementTypeButton
6x XCUIElementTypeOther
5x XCUIElementTypeStaticText
2x XCUIElementTypeTextField
2x XCUIElementTypeWindow
1x XCUIElementTypeStatusBar
1x XCUIElementTypeSwitch
1x XCUIElementTypeSlider
1x XCUIElementTypeApplication
nil
```

####その他のコマンド
以下参照   https://github.com/appium/ruby_lib/blob/master/docs/ios_docs.md

`textfields`や`buttons`などがよく使うのではないかと思います。


# 終わりに
久々にAppiumを触ってみた感想としては環境構築の部分はアップデートしないとダメでしたが、
テストコード自体は全く変更せずにサンプルを動かすことが出来ました。
UIAutomationのコードとXCUITestのコードでは文法も言語も異なるため、
Appiumがこうした差異を吸収してくれるのは嬉しいですね。
その反面Appium自体の学習コストなどもありますが、それについては今後別に検証・検討したいと思います。




# 参考URL
正直こっちの方がすごく良い記事ですね...。
http://qiita.com/k5n/items/899cf40a0021a6a92efd
http://qiita.com/k5n/items/6e81b5986361bd1e3cd0
http://qiita.com/k5n/items/086af8fe16af2924aaa8