AWS Device FarmをAppium + Ruby + RSpecで利用する

# 前置き
1月よりAWS Device FarmではAppium Rubyが[サポート](https://aws.amazon.com/jp/about-aws/whats-new/2019/01/aws-device-farm-now-supports-appium-nodejs-and-appium-ruby/)されています。過去にAppiumとRSpecの[記事](https://qiita.com/items/3cea66eb83280985d6cc)を投稿しており、過去のテストコードが活用できるか検証しました。本記事は[前記事](https://qiita.com/items/3cea66eb83280985d6cc)を振返りながらAndroid版のサンプルアプリで進めていきます。

# 構成
| 名前           | バージョン          |
| ------------- | ---------------- |
| macOS         | Mojave 10.14.4   |
| Homebrew      | 2.0.6            |

テストコードやテストパッケージなどを[GitHub](https://github.com/devnokiyo/aws-device-farm-appium-rspec)に公開しています。よろしければご覧ください。

# テストパッケージの作成
Device FarmでAppium Rubyを利用するには必要なパッケージとテストコードをzipファイルにアーカイブして、Device Farmにアップロードします。AWSの[ドキュメント](https://docs.aws.amazon.com/ja_jp/devicefarm/latest/developerguide/test-types-android-appium-ruby.html)に大まかな手順が記載されています。こちらに沿ってテストパッケージを作成していきます。余談ですがこのドキュメントの日本語版は3月から公開されたと思います。
## GPGをインストール
```bash
$ brew install gpg2
$ gpg  --help
gpg (GnuPG) 2.2.14
libgcrypt 1.8.4
Copyright (C) 2019 Free Software Foundation, Inc.
    :
    :
バグは <https://bugs.gnupg.org> までご報告ください。
```
## RVMをインストール
日頃はRubyのバージョン管理/切替えにrbenvを利用していますが、公式の手順で進めていきます。

1. RVMをインストール

    ```bash 
    $ gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
    $ curl -sSL https://get.rvm.io | bash
    Downloading https://github.com/rvm/rvm/archive/master.tar.gz
    Installing RVM to /Users/devnokiyo/.rvm/
        :
        :
    👉  Donate: https://opencollective.com/rvm/donate
    ```
1. パスを通す
    ```bash:~/.bash_profile
    export PATH="$PATH:$HOME/.rvm/bin"
    ```

    ```
    $ source ~/.bash_profile
    $ rvm -v
    rvm 1.29.7-next (master) by Michal Papis, Piotr Kuczynski, Wayne E. Seguin [https://rvm.io]
    ```
1. Rubyをインストール

    ```
    $ rvm install ruby 2.5.1 --autolibs=0
    Warning, new version of rvm available '1.29.7', you are using older version '1.29.7-next'.
    You can disable this warning with:    echo rvm_autoupdate_flag=0 >> ~/.rvmrc
    You can enable  auto-update  with:    echo rvm_autoupdate_flag=2 >> ~/.rvmrc
            :
            :
    Ruby was built without documentation, to build it run: rvm docs generate-ri

    $ ruby -v
    ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin18]
    ```

## テストパッケージの土台を準備する
1. ディレクトリ

    ```
    $ mkdir test_sample && cd $_
    ```
1. Gemfile / Gemfile.lock
前記事の[サンプル](https://github.com/devnokiyo/AppiumDemo)のGemfile / Gemfile.lockを配置します。
1. テストコード
まずは前記事の[サンプル](https://github.com/devnokiyo/AppiumDemo)のspecディレクトリと中身を配置します。後程Device Farm向けに修正します。

現時点での構成は以下のとおりです。

```
├── Gemfile
├── Gemfile.lock
└── spec
    ├── spec_helper.rb  # 後程修正します
    └── test.rb         # 後程修正します
```

## テストコードを修正する
「Device Farm」「エミュレーターではなく実機」という環境の変化によりテストコードを一部修正する必要があります。ここではファイル毎に主な変更点を記載します。githubにコミット履歴を作りましたので詳細は[こちら](https://github.com/devnokiyo/aws-device-farm-appium-rspec/commit/fbf63409f855155d1d3261e58c0fd0ebc92b38bf)でご確認ください。
### spec_helper.rb
Capabilitiesを変更します。

| Capability | 修正前 | 修正後 |
|---|---|---|
| automationName | Appium | UiAutomator2 |
| platformName | Android | 環境変数 DEVICEFARM_DEVICE_PLATFORM_NAME |
| deviceName | Android Emulator | 環境変数 DEVICEFARM_DEVICE_NAME |
| app | ./SampleApp/app-debug.apk | 環境変数 DEVICEFARM_APP_PATH |
| appPackage | com.example.devnokiyo.appiumdemo | - |
| appActivity | com.example.devnokiyo.appiumdemo.MainActivity | - |
| uuid | - | 環境変数 DEVICEFARM_DEVICE_UDID |
| avd | Pixel_2_API_28 | - |

環境変数についてはAWSの[ドキュメント](https://docs.aws.amazon.com/ja_jp/devicefarm/latest/developerguide/custom-test-environment-env.html)をご覧ください。

### test.rb
明示的にidを割当てていないダイアログのタイトルやボタンは[Appium Desktopで割出し](https://qiita.com/items/3cea66eb83280985d6cc#%E8%A3%9C%E8%B6%B3%E5%88%86%E3%81%8B%E3%82%89%E3%81%AA%E3%81%84id%E3%82%92%E5%89%B2%E5%87%BA%E3%81%99)ていました。このときはidの一部を省略してコンポーネントを指定していましたが、この状態ではDevice Farmが動作しませんでした。正式なidを指定すると動作します。("android:id/"を付与します。)

| id | 修正前 | 修正後 |
|---|---|---|
| 認証エラーダイアログ メッセージ | message | android:id/message |
| 認証エラーダイアログ OK | button2 | android:id/button2 |

## テストパッケージを仕上げる
テストコードパッケージの土台とテストコードの修正が完了したので、テストパッケージの完成をさせます。

1. bundlerをインストール
この記事ではなるべく過去のリソースを流用する主旨もあるのでバージョン1.17.1をインストールします。最新バージョンをインストールするとエラーが起こります。
[こちら](https://qiita.com/MotohiroSiobara/items/c0d343a160cffc2902ef)の記事を参考にさせて頂きました:smiley:

    ```bash
    $ gem install bundler -v 1.17.1
    Fetching: bundler-1.17.1.gem (100%)
    Successfully installed bundler-1.17.1
            :
            :
    1 gem installed
    
        $ bundler -v
    Bundler version 1.17.1
    ```

1. 各種Gemをインストール

     ```bash
    $ bundle install
    Fetching gem metadata from https://rubygems.org/..........
    Fetching eventmachine 1.2.7
    Installing eventmachine 1.2.7 with native extensions
            :
            :
    Bundle complete! 2 Gemfile dependencies, 20 gems now installed.
    Use `bundle info [gemname]` to see where a bundled gem is installed.
    ```

1.  Gemをキャッシュ
    ```bash
    $ bundle package
    Using eventmachine 1.2.7
    Using websocket-extensions 0.1.3
            :
            :
    Bundle complete! 2 Gemfile dependencies, 20 gems now installed.
    Use `bundle info [gemname]` to see where a bundled gem is installed.
    Updating files in vendor/cache
          * eventmachine-1.2.7.gem
          * websocket-extensions-0.1.3.gem
            :
            :
          * rspec-mocks-3.8.0.gem
          * rspec-3.8.0.gem
    ```

1. Zipでアーカイブ

    ```bash
    $ zip -r ../MyTests.zip Gemfile vendor/ spec/
      adding: Gemfile (deflated 7%)
      adding: vendor/ (stored 0%)
      adding: vendor/cache/ (stored 0%)
            :
            :
      adding: vendor/cache/websocket-driver-0.7.0.gem (deflated 14%)
    ```

これでDevice Farmにアップロードするテストパッケージが完成しました。同様のアーカイブを[GitHub](https://github.com/devnokiyo/aws-device-farm-appium-rspec/blob/master/test_package_archive/MyTests.zip
)にもアップロードしておきました。

# Device Farmの準備と実行
ここからはDevice FarmをAWSのコンソール(WEB)で操作していきます。
## プロジェクトを作成する
[Device Farm](https://us-west-2.console.aws.amazon.com/devicefarm/home?region=ap-northeast-1#/projects)のページに移動してプロジェクトを作成します。
![01.png](https://qiita-image-store.s3.amazonaws.com/0/240974/2c6f432a-9649-a87e-9681-47d24dfc4c32.png)
## 新しいテストケースを作成する
![02.png](https://qiita-image-store.s3.amazonaws.com/0/240974/c7b29a9d-e34e-5f23-eaea-a76381ae87c5.png)
## テスト対象のアプリをアップロードする
前記事の[サンプルアプリ](https://github.com/devnokiyo/AppiumDemo/blob/master/SampleApp/app-debug.apk)をアップロードします。当時と全く同じものです。
![03.png](https://qiita-image-store.s3.amazonaws.com/0/240974/3f919712-1a42-0a9d-a43a-d404610e8433.png)
## テストパッケージをアップロードする
テストフレームワークに`Appium Ruby`を選択して、前述のいくつかの手順で作成したテストパッケージ`MyTests.zip`をアップロードします。次の手順でテストスペックのYAMLを修正しますので、まだ「Next Step」を押さないでください。
![05.png](https://qiita-image-store.s3.amazonaws.com/0/240974/8a56b90f-f7de-3ce5-911a-42c84486c8a9.png)
## テストスペックのYAMLファイルを修正する
主な変更点を記載します。テストコードの説明と同様に詳細は[こちら](https://github.com/devnokiyo/aws-device-farm-appium-rspec/commit/fbf63409f855155d1d3261e58c0fd0ebc92b38bf)でご確認ください。

| Capability | 修正前 | 修正後 | 備考 |
|---|---|---|---|
| Appiumのバージョン | 1.7.2 | 1.9.1 | 1.10でテストしていたので出来るだけ最新バージョンを指定 |
| Appiumの引数 | chromedriver-executable | 削除 |  |
| プログラム実行 | bundle exec ruby YOUR_TEST_FILENAME.rb | bundle exec rspec spec/test.rb | 雛形から実プログラムへ書換え |

YAMLを書換えたら「Save Testspec」を押して適当な名前を付けておきます。
![06.png](https://qiita-image-store.s3.amazonaws.com/0/240974/e49bd3db-3a8c-187e-f24e-5e6143fa64de.png)
## テストする端末を選ぶ
デフォルトのデバイスプールとして「Top Devices」が選択されていました。
![07.png](https://qiita-image-store.s3.amazonaws.com/0/240974/e9777920-87ba-02cf-451f-41d09d8307dc.png)
よほどOSのバージョンが古くなければ何でも良いと思うのですが、筆者は以下のようにしました。
気分で選びました:stuck_out_tongue_winking_eye:
![08.png](https://qiita-image-store.s3.amazonaws.com/0/240974/3d630b04-47cd-d3da-4c69-6c72748dbad4.png)
余談ですが無料枠は端末の利用時間で減っていくようで、動作時間×端末数で時間がカウントされています。雛形を作っている最中は1つの端末のみを指定して試行錯誤すると良いと思います。
## 付加情報を指定する
特に指定することがありませんので「Next Step」を押します。
![09.png](https://qiita-image-store.s3.amazonaws.com/0/240974/15ca3f40-0f34-8dee-1dfe-13d8856f9b70.png)
## 実行の設定をする
特に指定することがありませんので「Next Step」を押します。ただ、ある程度動作確認が取れるまではタイムアウトの時間を小さくすると良いと思います。根拠はありませんが筆者は10分くらいで試していました。
![10.png](https://qiita-image-store.s3.amazonaws.com/0/240974/551d53ca-d0ad-7060-1d97-b53c84640bdf.png)
「Confirm and start run」を押して実行しましょう。

# Device Farmの動作状況とテスト結果を見る
テストコードが動作しているかをDevice Farmのコンソールで見ていきます。Device Farmのページのスクリーンショットが多く、AppiumとかRSpecはあまり関係のないようにも思いますが、折角なのでテストの進行状況を見てみましょう:hugging:
通常業務なら「自動テストなんだから放っておく」ことになりますよね。
## 動作状況を見る
前手順で「Confirm and start run」を押すとテストケースのリストページに遷移します。

1. テストケースを選択
Runの「app-debug.apk」をクリックします。
![11.png](https://qiita-image-store.s3.amazonaws.com/0/240974/2b6330df-6c9b-e940-7d72-e1a8287a9d63.png)

1. 端末を選択
とりあえず「Pixel 2」で状況を見てみます。
![12.png](https://qiita-image-store.s3.amazonaws.com/0/240974/f7529a5a-c6df-e4fa-efdf-027bab205198.png)

1. 進捗をグラフィカルに見る
コンソールに表示されているとおり数分待ちます。
![13.png](https://qiita-image-store.s3.amazonaws.com/0/240974/ac022941-2345-5287-557a-8f5c227c14b3.png)
端末の画面が表示されました。
![14.png](https://qiita-image-store.s3.amazonaws.com/0/240974/7ad34c46-d2bf-7d76-0399-cac5dbbda6b8.png)
テストコードが実行されました。
![15.png](https://qiita-image-store.s3.amazonaws.com/0/240974/11c66e8f-6b85-79a4-b74b-eb6120ba4592.png)
テストが終わりました。`5 examples, 0failures`:thumbsup:
![16.png](https://qiita-image-store.s3.amazonaws.com/0/240974/ed5217c2-bf3c-d94f-4e50-28357d09ce92.png)

1. 全体的な進捗を見る
Galaxy S10もテストをパスしていることがわかります。
![17.png](https://qiita-image-store.s3.amazonaws.com/0/240974/474769d7-2700-4766-de1b-ffe7fd3e79c7.png)

# 終わりに
筆者は日頃、UIの自動テストに従事しておらず、UIの自動テストについて定番の構成を理解していません。Device Farm自体の情報量が少ない印象で、更にAppium Ruby RSpecという構成による事例が見当たらなかったので調査してみました。むしろ、これから対応のフレームワークが増えていって利用される機会が増えるのかもしれません。機会があればiOSでも実行できるか確認してみたいと思います。