AWS Device Farm を使ってモバイル向け Web アプリをクラウドでテストする #アドカレ2015
AWS Device Farm が Web アプリに対応
AWS Device Farm (以下 Device Farm)は、モバイルアプリをクラウドでテストするためのサービスです。AWS クラウド上で、実際のスマホやタブレットを使ったテストを実施することができます。iOS / Android / Fire OS のデバイス、様々な OS バージョンの中からテストしたいデバイスを自由に選択し、自分のアプリを簡単にテストすることができます。
2015年11月に、Device Farm が Web アプリをサポートしました。これまではアプリが対象でしたが、モバイル向けの Web アプリを対象にテストすることもできます。
モバイル向けの Web アプリの品質を向上するためには、モバイルアプリと同様、様々なデバイスや OS バージョンでテストする必要があります。デバイスの大きさも、ブラウザの種類も多種多様ですので、開発中のデバイスでは正常に動いていたのに、いざ公開してみると「あるデバイスでは表示が崩れてしまう」、「このブラウザではおかしな挙動をしてしまう」といったようなことがよくあります。
Device Farm を使うことで、手元に実機を用意する必要なく、様々なデバイスを対象に簡単にテストが行えます。Web アプリの品質向上には必須のサービスと言えるでしょう。
ということで、本記事が掲載されているブログ「Developers.IO」を Device Farm で簡単にテストしてみました。
Appium とは?
Device Farm で Web アプリをテストするには Appium を使います。
Appium は、主にモバイルアプリを自動でテストのためのツールです。「Selenium のアプリ版」という位置付けのツールです。なお、Selenium は PC ブラウザを自動で操作して Web サイトをテストできるツールです。Selenium でできることがモバイルアプリを対象に行えるものとなっています。
Device Farm で Web アプリをテストは現在 Appium のみ対応していますので、Appium を使って書かれたテストコードが必要になります。と言っても、そこまで難しいものではありません。
Appium の動作環境を構築する
まずは、Appium の動作環境をローカルで構築しましょう。なお、Xcode または Android Studio は導入されている前提で進めます。これらが必要な理由は、Appium は Web アプリの自動操作を iOS シミュレータまたは Android エミュレータで行うためです。
Appium は Node.js 上で動作するツールのため、Node.js をインストールしましょう。今回は v0.12.8
を使用しました。
$ brew install node $ node -v v0.12.8
なお、Homebrew を導入されていない場合、上記コマンドは叩けません。その場合は Homebrew をインストールしましょう。
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
次に appium
をインストールします。また、Web ページを操作するためのモジュール wd
もインストールします。ios-webkit-debug-proxy
は Web ページをデバッグするために必要なツールです。
$ npm install -g appium $ npm install wd $ brew install ios-webkit-debug-proxy $ appium -v 1.4.16
次に appium-doctor
コマンドを使って、環境設定が正常かどうかチェックします。エラーが出た場合は、どの環境変数がセットされていないか詳細に表示されます。その場合は設定を見直してください。なお、--ios
や --android
を付けると、いずれかだけ確認することができます。
$ appium-doctor Running iOS Checks ✔︎ Xcode is installed at /Applications/Xcode.app/Contents/Developer ✔︎ Xcode Command Line Tools are installed. ✔︎ DevToolsSecurity is enabled. ✔︎ The Authorization DB is set up properly. ✔︎ Node binary found at /usr/local/bin/node ✔︎ iOS Checks were successful. Running Android Checks ✔︎ ANDROID_HOME is set to "/Applications/android-sdk-macosx" ✔︎ JAVA_HOME is set to "/usr/bin/java." ✔︎ ADB exists at /Applications/android-sdk-macosx/platform-tools/adb ✔︎ Android exists at /Applications/android-sdk-macosx/tools/android ✔︎ Emulator exists at /Applications/android-sdk-macosx/tools/emulator ✔︎ Android Checks were successful. ✔︎ All Checks were successful
以上で、Appium の導入は完了です。
テストコードを書く
次に、テストコードを書きます。
Device Farm で Web アプリをテストするためのフレームワークは Appium + JUnit か Appium + TestNG が対応しています。今回は JUnit を使ってみます。サンプルコードは GitHub に公開していますので、ぜひ参照頂ければと思います。
なお、プロジェクトは Maven を使ってビルドを行います。Maven をインストールしていない場合、以下のコマンドを叩いてインストールを行っておきます。
$ brew install maven
プロジェクトには、最低限次の3つのファイルが必要になります。
pom.xml
: プロジェクト設定の定義ファイル (依存関係のあるライブラリの定義など)zip.xml
: Zip ファイル形式に圧縮する条件を指定するファイルWebAppTest.java
: テストコード (ファイル名、クラス名は自由に設定可能)
フォルダ構成は次のようになります。src/test/java
以下はテストクラスのパッケージに依るので、適宜読み替えてください。
. ├── pom.xml └── src ├── main │ └── assembly │ └── zip.xml └── test └── java └── jp └── classmethod └── dev └── WebAppTest.java
まず pom.xml
と zip.xml
を用意しましょう。pom.xml
には Appium による自動テストに必要なライブラリなどの定義を書きます。 zip.xml
には JAR ファイルを対象に Zip 圧縮する定義を書きます。これらのファイルはちょっと長いので割愛します。詳細は以下に公開してあるファイルを参照してください。
次に、テストコードを書きます。以下のようなプログラムがミニマムな構成かと思います。
package jp.classmethod.dev.test; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.OutputType; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.remote.DesiredCapabilities; import io.appium.java_client.ios.IOSDriver; import java.net.URL; import java.io.File; import static org.junit.Assert.*; public class WebAppTest { private WebDriver driver; @Before public void setUp() throws Exception { DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability("deviceName", "iPhone 6"); capabilities.setCapability("platformName", "iOS"); capabilities.setCapability("platformVersion", "9.1"); capabilities.setCapability("browserName", "safari"); driver = new IOSDriver<WebElement>(new URL("http://127.0.0.1:4723/wd/hub"), capabilities); } @Test public void runTest() throws Exception { // Web サイトにアクセス driver.get("https://dev.classmethod.jp"); // 1秒待機 Thread.sleep(1000); // class が "logo" のエレメントを探す WebElement idElement = driver.findElement(By.className("logo")); // 取得できたかチェックする assertNotNull(idElement); // "Developers.IO" になっているかチェックする assertEquals("Developers.IO", idElement.getText()); // スクリーンショットを撮る takeScreenshot("Top Page"); } public boolean takeScreenshot(final String name) { String screenshotDirectory = System.getProperty("appium.screenshots.dir", System.getProperty("java.io.tmpdir", "")); File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); return screenshot.renameTo(new File(screenshotDirectory, String.format("%s.png", name))); } @After public void tearDown() throws Exception { driver.quit(); } }
解説します。まずメンバーとして定義している WebDriver は、シミュレータ(またはエミュレータ) を操作するためのインターフェースです。このインターフェースに定義されているメソッドを使うと、Web ページにアクセスしたり、エレメントを取得したりすることができます。
setUp()
では、テストを実施する前の準備を行います。このメソッドの最後の行で driver
に IOSDriver を代入していますが、これは iOS シミュレータを対象とする場合の設定です。Device Farm で動作する上では iOS と Android のいずれも対象とすることができますが、ここの設定は良しなにやってくれているようです(おそらく) *1。
runTest()
が、実際のテスト内容になります。今回は、Developers.IO にアクセスし、class が logo
のエレメントを取ってきて、そのテキストが「Developers.IO」であるかどうかをテストしています。対象のエレメントは以下のような感じです。
<a class="logo" href="https://dev.classmethod.jp/" title="AWS/iOS技術者の必読メディア:クラスメソッド株式会社ブログ" rel="home">Developers.IO</a>
最後の行ではスクリーンショットの撮影処理を行っています。TakeScreenshot はスクリーンショットを撮影するためのクラスです。appium.screenshots.dir
というプロパティにアクセスすると、スクリーンショットの保存場所が取得できます。
ここまで出来たら、テストをローカルで試しつつ Zip 形式にまとめましょう。まず Appium を起動します。--no-reset
はテスト終了後にシミュレータ(エミュレータ)を初期化しないためのオプションです。
$ appium --no-reset &
次に、プロジェクトのルート (pom.xml
が置いてあるディレクトリ) で以下のコマンドを実行します。
$ mvn clean package
iOS シミュレータが自動で起動し、テストが実行されると思います。なお、テストの実行をスキップしたい場合は -DskipTests=true
オプションを付与します。なお、このオプションを付けてパッケージングした場合は Appium は使われません *2。
$ mvn clean package -DskipTests=true
テストが終わると、必要なファイル一式を Zip 形式に圧縮する処理が行われます。すべての処理が終わると targets
ディレクトリが生成され、その中に zip-with-dependencies.zip
というファイルが生成されます。このファイルを Device Farm にアップロードすることになります。
Device Farm でテストを実施する
いよいよ Device Farm の登場です。先ほど作成した zip-with-dependencies.zip
をアップロードし、クラウド上でテストを実施しましょう。
まずプロジェクトを作成し、新規の Run を作ります。Run name は「Developers.IO」としました。
次にテスティングフレームワークを選択します。今回は「Appium Java JUnit」を選択し、「Upload」をクリックし、zip-with-dependencies.zip
をアップロードします。
次にデバイスの選択です。今回は、iOS と Android、デバイスが1台ずつ含まれる Device Pool を作成しました。計2台のデバイスを対象となっています。
最後は全設定の確認画面です。「Confirm and start run」をクリックし、いよいよテストの実行です。
テストが成功すると、緑色でわかりやすく表示されます。
スクリーンショットもバッチリ撮れていますね *3。
まとめ
Appium の知識が若干必要ですが、手順通り進めれば良いのでそこまでハードルは高くありません。JUnit のテストコードを書きましたが、対象のエレメントが期待した結果になっているか確認するだけであればそこまで手間にならないと思います。また、Selenium をすでに導入されているのであれば、テストコードはほとんど流用できるでしょう。ぜひ、利用してみてください。
明日(12月6日)は都元ダイスケの Amazon SNS に関する記事です。お楽しみに!
参考情報
本記事の内容を調査するにあたって、参考になった記事をまとめました。私が Appium を触ったこと自体なかったので、Device Farm に直接的に関係のない記事も含まれています。
概要
- Amazon Web Services ブログ: AWS Device Farm で Web モバイルアプリのテストができるようになりました
- Working with Custom Web App Tests in AWS Device Farm - AWS Device Farm
Appium の使い方
- Automating mobile web apps | appium/appium (GitHub)
- 「Appiumの使い方」を分かり易くまとめてみました!│ソフトウェアテストラボ|アプリテスト|スマートフォンテスト|株式会社シフト
Selenium の使い方
Device Farm の使い方
- Working with Appium Java JUnit for iOS and AWS Device Farm - AWS Device Farm
- Working with Appium Java JUnit for Android and AWS Device Farm - AWS Device Farm
- Working with Appium Java JUnit for Web Applications and AWS Device Farm - AWS Device Farm