AWS Device FarmでAndroidのアプリをテストしてみたよ！

#はじめに

こんにちはー！[@あれれちゃん](https://twitter.com/ArereSearch?lang=ja)です。
皆さんテストしてますか？

最近素敵なテストソリューションが続々登場していますね♪

我らが「あれれサーチ」
本家サイト：https://arere.applihelp.com/?qi

CybarAgentの「STF」オープンソース化
本家サイト：https://openstf.github.io/
ブログ記事：https://www.cyberagent.co.jp/techinfo_detail/id=10707

Googleの「CloudTestLab」発表（←まだ使えないよ～）
本家サイト：https://developers.google.com/cloud-test-lab/
ブログ記事：http://gori.me/google/google-news/77659

そしてこの、AWS DeviceFarm
本家サイト：http://aws.amazon.com/jp/device-farm/
ブログ記事：http://jp.techcrunch.com/2015/07/10/20150709amazon-launches-aws-device-farm-lets-developers-test-android-and-fire-os-apps-on-real-devices/
先週末の7/10に突然の発表、昨日ローンチされました！（2015/7/15現在）

もう、テスト端末を手に入れるための時間や場所の制約がどんどん取り除かれていますね！


#AWS Device Farmってなぁに？

###・どんなことできるの？
ざっくり言うと、遠隔地にあるAndroidやFireOSデバイスに自分がテストしたいアプリをインストールしてテストできるよ！ってサービスです。
適当に大量のイベントを流し込んでテストするFuzzテストや、テストスクリプトを流すこともできます。

###・料金は？
端末利用時間の合計が250分まではタダで使えます。
それ以降が有料。1端末1分あたりあたり$0.17 です。現在だと、およそ21円/分ですね。

###・ざっくりどんな流れなの？
簡単に流れを書いておくと
　1.AWSにログインしDeviceFarm選択
　2.テストしたいapkをUP
　3.テストの種類を選択（Fuzzテストか、テストスクリプト流すか、とか）
　4.デバイス選択
　5.デバイスの状態を設定（他のアプリ入れたり、WiFiをONにしたり、言語設定したり、とか）
　6.実行！あとは待つのみ。

#使ってみたよ
手順の説明はAWSのブログにかなり詳しく書かれてあります。
http://aws.typepad.com/aws_japan/2015/07/aws-device-farm-test-mobile-apps-on-real-devices.html

自分も使いながらキャプチャ撮ったので↑ここに載っていない画面は載せておきます。

とりあえず、AWSマネジメントコンソールにログインしたら、DeviceFarmを選択。
![AWS1.PNG](https://qiita-image-store.s3.amazonaws.com/0/32732/bd9fbcb7-bf25-7ec0-846f-136f713880d0.png)
リージョンを選択（と言っても今は米国西部しかないみたい）
![aws2.PNG](https://qiita-image-store.s3.amazonaws.com/0/32732/1d179d6f-1390-17de-ba4a-5b3e7bfa57e5.png)

すると利用開始できます。
これ以降は[AWSのブログ](http://aws.typepad.com/aws_japan/2015/07/aws-device-farm-test-mobile-apps-on-real-devices.html)のままなので、説明は省きます。

2つのアプリで試しにAWS DeviceFarm使ってみました。
テストスクリプト（Appium、Calabash、uiautomator 。また、JUnit、Robotium、Espresso を使った Instrumentation テストも実行できます）を流すこともできますが、とりあえず今回はBuild-in：Fuzzテストのみ。


##　①サーバにテキストを送るアプリでテスト
実施したイベントがログに残るのだけど、テストの状況を動画で見れるわけではないので、いまいち何が行われているのかわかんないなぁ…と個人的には思いました。
で、[アプリヘルプ](http://www.applihelp.com/)という問合せフォームSDKを設置しただけのアプリを用意しました。

アプリの利用者が問合せフォームから問合せすると、その内容をアプリサポート担当がWebコンソールで確認できるようになっています。
イメージはこんな感じ
![applihelp_image.PNG](https://qiita-image-store.s3.amazonaws.com/0/32732/b8487e19-55d1-ac27-8d19-1d160de39f32.png)

このアプリをテストして、どんなテキストがサポート担当（Web側）に送られてくるか見てみます。
（テストはBuild-in：Fuzzで、6000イベントを実行）

【結果】
![apphelp_awsdevfarm_msg.PNG](https://qiita-image-store.s3.amazonaws.com/0/32732/c0238d9b-6c05-d154-9083-6c964eb39750.png)
こんな感じで瞬時に50通のメッセージがサーバに送られてきました。
6000イベント恐るべし…

##　②-1わざとクラッシュを仕込んだアプリをテスト
重要なのはバグを本当に見つけられるかです！
試してみましょう。

わざと複数のクラッシュバグを仕込んだapkをUPしてみました。
仕込んだバグは以下6つ
いずれかのイベントが発生すると強制的にクラッシュするようにバグを仕込んでいます。
・画面を回転
・アプリを合計3回起動
・テキストボックスに1000文字入力
・テキストボックスに空入力で、あるボタンを長押し
・言語環境を日本語以外を選択
・消去ボタンを20回押す

【結果】
6つ仕込んだバグのうち、1つ見つけて来ましたね。
![aws_bugtest3.PNG](https://qiita-image-store.s3.amazonaws.com/0/32732/5112bef8-e3b7-3e71-6282-37ccf3e2e456.png)

（※ピンク色の帯の部分。バグの内容が日本語で出力されているのは、日本語でエラーを吐くようにプログラムを書いてるだけです。DeviceFarmの機能ではありません）
よく見てみると、
Exerciser detected crash after 686 events
「Exerciserは686のイベントの後にクラッシュを検出しました」と書かれてあります。

検出されたクラッシュは「言語環境を日本語以外を選択」のみ。
他のクラッシュは見つかりませんでした。

テスト後にログファイルがダウンロードできます。
![aws_bugtest4.PNG](https://qiita-image-store.s3.amazonaws.com/0/32732/66d1dda3-baa8-fc25-8406-edb9f5922c50.png)

Exerciser Monkey Logをダウンロードして見てみました。
内容はこんな感じ（修正して一部抜粋）

```
～略～
:Sending Key (ACTION_DOWN): 21    // KEYCODE_DPAD_LEFT
:Sending Key (ACTION_UP): 21    // KEYCODE_DPAD_LEFT
Sleeping for 50 milliseconds
:Sending Key (ACTION_DOWN): 19    // KEYCODE_DPAD_UP
:Sending Key (ACTION_UP): 19    // KEYCODE_DPAD_UP
Sleeping for 50 milliseconds
:Sending Touch (ACTION_DOWN): 0:(742.0,1270.0)
:Sending Touch (ACTION_UP): 0:(758.264,1269.401)
Sleeping for 50 milliseconds
    // Allowing start of Intent { cmp=***.***.***/.MainActivity } in package ***.***.***
    // activityResuming(***.***.***)
:Sending Key (ACTION_DOWN): 20    // KEYCODE_DPAD_DOWN
// CRASH: ***.***.*** (pid 16773)
// Short Msg: java.lang.RuntimeException
// Long Msg: java.lang.RuntimeException: 言語環境が日本語以外
// Build Label: Verizon/kltevzw/kltevzw:4.4.4/KTU84P/G900VVRU1ANK2:user/release-keys
// Build Changelist: G900VVRU1ANK2
// Build Time: 1416220429000
// java.lang.RuntimeException: Unable to start activity ComponentInfo{***.***.***/***.***.***.MainActivity}: java.lang.RuntimeException: 
言語環境が日本語以外
// 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2438)
// 	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2497)
// 	at android.app.ActivityThread.access$900(ActivityThread.java:168)
// 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1306)
// 	at android.os.Handler.dispatchMessage(Handler.java:102)
// 	at android.os.Looper.loop(Looper.java:146)
// 	at android.app.ActivityThread.main(ActivityThread.java:5678)
// 	at java.lang.reflect.Method.invokeNative(Native Method)
// 	at java.lang.reflect.Method.invoke(Method.java:515)
// 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
// 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
// 	at dalvik.system.NativeStart.main(Native Method)
// Caused by: java.lang.RuntimeException: 言語環境が日本語以外
// 	at ***.***.***.MainActivity.onCreate(MainActivity.java:57)
// 	at android.app.Activity.performCreate(Activity.java:5586)
// 	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1093)
// 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2402)
// 	... 11 more
// 
** Monkey aborted due to error.
Events injected: 686
:Sending rotation degree=0, persist=false
:Dropped: keys=1 pointers=0 trackballs=0 flips=0 rotations=0
## Network stats: elapsed time=21371ms (0ms mobile, 0ms wifi, 21371ms not connected)
** System appears to have crashed at event 686 of 6000 using seed 1437945616718
```
どうやらクラッシュ時にテストが止まって、以降のイベントは行われませんね。バグなのか仕様なのか。。

##　②-2　わざとクラッシュを仕込んだアプリをテスト（言語設定：日本語）
先ほどバグ検出して止まってしまったので言語設定を日本語にしてもう一度テストしてみます。

【結果】
バグなし。。。
6000イベント全て通っちゃいました。
なので、Fuzzテストは画面回転や1000文字以上のテキスト入力などのテストをしてないようですね。
（ちなみに2回行いましたが結果は同じでした）
![aws_bugtest5.PNG](https://qiita-image-store.s3.amazonaws.com/0/32732/2120c5c7-975c-db35-4932-3b7a7283c838.png)

#利用料金(残テスト時間)の確認
* メニューの「サービス」⇒「請求」を選択します
 * ![df1.png](https://qiita-image-store.s3.amazonaws.com/0/19778/a3fa378b-24f8-5745-6be5-44ad3781ae61.png)
* 表示されたページで「請求書」を選択します
 * ![df2.png](https://qiita-image-store.s3.amazonaws.com/0/19778/32a16f22-2d0a-f89f-7bea-282f6c986d8c.png)
* スクロールすればDeviceFarmの明細が表示されます
 * ![df3.png](https://qiita-image-store.s3.amazonaws.com/0/19778/de94334b-df12-022e-e03a-ec3d27d031fc.png)
 * スクショは無料枠で使用中、30分程使ったという状態です。


#サービスはまだ不安定（2015/7/15現在）
まだリリースしたばかりなので不安定な部分もありますね。
感想にも書きましたが、利用中の端末のテストが終わらないというアクシデントが発生しました。他の方々も発生しているようです。

@oh_rusty_nail さんがQ&Aに寄せられた内容をまとめてくださったので、以下をご覧ください。

#DeviceFarmのフォーラムに寄せられたQ&A
* フォーラムページは[こちら](https://forums.aws.amazon.com/forum.jspa?forumID=193&start=0)
 * 投稿されたQ&Aをまとめてみましたが、「テストが止まりません、止まらないと料金が永遠にかかるのでは>_< ｺﾜｲ」 という内容が多かったです
* Q1: 実行したテストは中断/キャンセルできないのか？
 * A1: 中断/キャンセル機能は提供されていないため出来ません。また終了しないでお困りな方はPrivateMessageでテストのURLを送信していただければ調査します
* Q2: Appiumを使ったテストのスクリーンショットが取れません
 * A2: Appiumのスクリーンショットはサポートされていません
* Q3: 現在の利用時間/料金はどのような方法で確認できますか？
 * A3: (本Qiita記事を参照してください)
* Q4: 作成したプロジェクトの削除はできますか？
 * A4: プロジェクトの削除機能は提供されていません
* Q5: サービス側の異常と思われる終了されないテストについては料金が発生するのか？
 * A5: 料金は発生しません。テストのURLをいただければ停止作業をします。

#感想
まだまだ発展途上とういう気がしました。
例えば、「①サーバにテキストを送るアプリでテスト」は3つの端末を選択してテストを行ったのですが、2つの端末は5分ほどでテストが完了したにもかかわらず、残りの1つHTC One M9 (AT&T)が1時間ほど経っても終わらないというアクシデントが発生しました。

~~250分は無料でも、このまま動き続けたら料金が発生してしまいます。~~
しかし、停止させる手段は見当たりませんでした。
なお、Q&AのQ5にもありますが、料金は発生しないとのことです。

~~サポートに「AWS DeviceFarmのテスト終了方法が分からない」旨の問い合わせをしたら「技術的なサポートは有料、無料だったらフォーラムで投稿すれば解決するかもしれない」旨の返答。
正直ちょっと怖いなーという印象でした。
幸い1.5時間ほどすると止まってくれたので、事なきを得てホッとしました。~~

改善を待ちましょう。

あと、iOSへの対応ができるようになると良いですね。

以上、[@あれれちゃん](https://twitter.com/ArereSearch?lang=ja)より、AWS DeviceFarmの使ってみた感想でした。